Home | History | Annotate | Download | only in extensions
      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
      3 // found in the LICENSE file.
      4 
      5 #include "chrome/browser/extensions/crx_installer.h"
      6 
      7 #include <map>
      8 #include <set>
      9 
     10 #include "base/bind.h"
     11 #include "base/file_util.h"
     12 #include "base/files/scoped_temp_dir.h"
     13 #include "base/lazy_instance.h"
     14 #include "base/metrics/histogram.h"
     15 #include "base/path_service.h"
     16 #include "base/sequenced_task_runner.h"
     17 #include "base/strings/string_util.h"
     18 #include "base/strings/stringprintf.h"
     19 #include "base/strings/utf_string_conversions.h"
     20 #include "base/threading/sequenced_worker_pool.h"
     21 #include "base/threading/thread_restrictions.h"
     22 #include "base/time/time.h"
     23 #include "base/version.h"
     24 #include "chrome/browser/chrome_notification_types.h"
     25 #include "chrome/browser/extensions/convert_user_script.h"
     26 #include "chrome/browser/extensions/convert_web_app.h"
     27 #include "chrome/browser/extensions/crx_installer_error.h"
     28 #include "chrome/browser/extensions/extension_assets_manager.h"
     29 #include "chrome/browser/extensions/extension_error_reporter.h"
     30 #include "chrome/browser/extensions/extension_install_ui.h"
     31 #include "chrome/browser/extensions/extension_service.h"
     32 #include "chrome/browser/extensions/install_tracker.h"
     33 #include "chrome/browser/extensions/install_tracker_factory.h"
     34 #include "chrome/browser/extensions/permissions_updater.h"
     35 #include "chrome/browser/extensions/webstore_installer.h"
     36 #include "chrome/browser/profiles/profile.h"
     37 #include "chrome/browser/web_applications/web_app.h"
     38 #include "chrome/common/chrome_paths.h"
     39 #include "chrome/common/extensions/extension_constants.h"
     40 #include "chrome/common/extensions/manifest_url_handler.h"
     41 #include "content/public/browser/browser_thread.h"
     42 #include "content/public/browser/notification_service.h"
     43 #include "content/public/browser/resource_dispatcher_host.h"
     44 #include "content/public/browser/user_metrics.h"
     45 #include "extensions/browser/extension_prefs.h"
     46 #include "extensions/browser/extension_system.h"
     47 #include "extensions/browser/install_flag.h"
     48 #include "extensions/common/extension_icon_set.h"
     49 #include "extensions/common/feature_switch.h"
     50 #include "extensions/common/file_util.h"
     51 #include "extensions/common/manifest.h"
     52 #include "extensions/common/manifest_handlers/kiosk_mode_info.h"
     53 #include "extensions/common/manifest_handlers/shared_module_info.h"
     54 #include "extensions/common/permissions/permission_message_provider.h"
     55 #include "extensions/common/permissions/permission_set.h"
     56 #include "extensions/common/permissions/permissions_data.h"
     57 #include "extensions/common/user_script.h"
     58 #include "grit/chromium_strings.h"
     59 #include "grit/extensions_strings.h"
     60 #include "grit/generated_resources.h"
     61 #include "grit/theme_resources.h"
     62 #include "third_party/skia/include/core/SkBitmap.h"
     63 #include "ui/base/l10n/l10n_util.h"
     64 #include "ui/base/resource/resource_bundle.h"
     65 
     66 #if defined(OS_CHROMEOS)
     67 #include "chrome/browser/chromeos/login/users/user_manager.h"
     68 #endif
     69 
     70 using base::UserMetricsAction;
     71 using content::BrowserThread;
     72 using extensions::SharedModuleInfo;
     73 
     74 namespace extensions {
     75 
     76 namespace {
     77 
     78 // Used in histograms; do not change order.
     79 enum OffStoreInstallDecision {
     80   OnStoreInstall,
     81   OffStoreInstallAllowed,
     82   OffStoreInstallDisallowed,
     83   NumOffStoreInstallDecision
     84 };
     85 
     86 }  // namespace
     87 
     88 // static
     89 scoped_refptr<CrxInstaller> CrxInstaller::CreateSilent(
     90     ExtensionService* frontend) {
     91   return new CrxInstaller(frontend->AsWeakPtr(),
     92                           scoped_ptr<ExtensionInstallPrompt>(),
     93                           NULL);
     94 }
     95 
     96 // static
     97 scoped_refptr<CrxInstaller> CrxInstaller::Create(
     98     ExtensionService* frontend,
     99     scoped_ptr<ExtensionInstallPrompt> client) {
    100   return new CrxInstaller(frontend->AsWeakPtr(), client.Pass(), NULL);
    101 }
    102 
    103 // static
    104 scoped_refptr<CrxInstaller> CrxInstaller::Create(
    105     ExtensionService* service,
    106     scoped_ptr<ExtensionInstallPrompt> client,
    107     const WebstoreInstaller::Approval* approval) {
    108   return new CrxInstaller(service->AsWeakPtr(), client.Pass(), approval);
    109 }
    110 
    111 CrxInstaller::CrxInstaller(base::WeakPtr<ExtensionService> service_weak,
    112                            scoped_ptr<ExtensionInstallPrompt> client,
    113                            const WebstoreInstaller::Approval* approval)
    114     : install_directory_(service_weak->install_directory()),
    115       install_source_(Manifest::INTERNAL),
    116       approved_(false),
    117       expected_manifest_check_level_(
    118           WebstoreInstaller::MANIFEST_CHECK_LEVEL_STRICT),
    119       expected_version_strict_checking_(false),
    120       extensions_enabled_(service_weak->extensions_enabled()),
    121       delete_source_(false),
    122       create_app_shortcut_(false),
    123       service_weak_(service_weak),
    124       // See header file comment on |client_| for why we use a raw pointer here.
    125       client_(client.release()),
    126       apps_require_extension_mime_type_(false),
    127       allow_silent_install_(false),
    128       grant_permissions_(true),
    129       install_cause_(extension_misc::INSTALL_CAUSE_UNSET),
    130       creation_flags_(Extension::NO_FLAGS),
    131       off_store_install_allow_reason_(OffStoreInstallDisallowed),
    132       did_handle_successfully_(true),
    133       error_on_unsupported_requirements_(false),
    134       update_from_settings_page_(false),
    135       install_flags_(kInstallFlagNone),
    136       installer_(service_weak->profile()) {
    137   installer_task_runner_ = service_weak->GetFileTaskRunner();
    138   if (!approval)
    139     return;
    140 
    141   CHECK(profile()->IsSameProfile(approval->profile));
    142   if (client_) {
    143     client_->install_ui()->SetUseAppInstalledBubble(
    144         approval->use_app_installed_bubble);
    145     client_->install_ui()->set_skip_post_install_ui(
    146         approval->skip_post_install_ui);
    147   }
    148 
    149   if (approval->skip_install_dialog) {
    150     // Mark the extension as approved, but save the expected manifest and ID
    151     // so we can check that they match the CRX's.
    152     approved_ = true;
    153     expected_manifest_check_level_ = approval->manifest_check_level;
    154     if (expected_manifest_check_level_ !=
    155         WebstoreInstaller::MANIFEST_CHECK_LEVEL_NONE)
    156       expected_manifest_.reset(approval->manifest->DeepCopy());
    157     expected_id_ = approval->extension_id;
    158   }
    159   if (approval->minimum_version.get()) {
    160     expected_version_.reset(new Version(*approval->minimum_version));
    161     expected_version_strict_checking_ = false;
    162   }
    163 
    164   show_dialog_callback_ = approval->show_dialog_callback;
    165   set_is_ephemeral(approval->is_ephemeral);
    166 }
    167 
    168 CrxInstaller::~CrxInstaller() {
    169   // Make sure the UI is deleted on the ui thread.
    170   if (client_) {
    171     BrowserThread::DeleteSoon(BrowserThread::UI, FROM_HERE, client_);
    172     client_ = NULL;
    173   }
    174 }
    175 
    176 void CrxInstaller::InstallCrx(const base::FilePath& source_file) {
    177   ExtensionService* service = service_weak_.get();
    178   if (!service || service->browser_terminating())
    179     return;
    180 
    181   NotifyCrxInstallBegin();
    182 
    183   source_file_ = source_file;
    184 
    185   scoped_refptr<SandboxedUnpacker> unpacker(
    186       new SandboxedUnpacker(source_file,
    187                             install_source_,
    188                             creation_flags_,
    189                             install_directory_,
    190                             installer_task_runner_.get(),
    191                             this));
    192 
    193   if (!installer_task_runner_->PostTask(
    194           FROM_HERE,
    195           base::Bind(&SandboxedUnpacker::Start, unpacker.get())))
    196     NOTREACHED();
    197 }
    198 
    199 void CrxInstaller::InstallUserScript(const base::FilePath& source_file,
    200                                      const GURL& download_url) {
    201   DCHECK(!download_url.is_empty());
    202 
    203   NotifyCrxInstallBegin();
    204 
    205   source_file_ = source_file;
    206   download_url_ = download_url;
    207 
    208   if (!installer_task_runner_->PostTask(
    209           FROM_HERE,
    210           base::Bind(&CrxInstaller::ConvertUserScriptOnFileThread, this)))
    211     NOTREACHED();
    212 }
    213 
    214 void CrxInstaller::ConvertUserScriptOnFileThread() {
    215   base::string16 error;
    216   scoped_refptr<Extension> extension = ConvertUserScriptToExtension(
    217       source_file_, download_url_, install_directory_, &error);
    218   if (!extension.get()) {
    219     ReportFailureFromFileThread(CrxInstallerError(error));
    220     return;
    221   }
    222 
    223   OnUnpackSuccess(extension->path(), extension->path(), NULL, extension.get(),
    224                   SkBitmap());
    225 }
    226 
    227 void CrxInstaller::InstallWebApp(const WebApplicationInfo& web_app) {
    228   NotifyCrxInstallBegin();
    229 
    230   if (!installer_task_runner_->PostTask(
    231           FROM_HERE,
    232           base::Bind(&CrxInstaller::ConvertWebAppOnFileThread, this, web_app)))
    233     NOTREACHED();
    234 }
    235 
    236 void CrxInstaller::ConvertWebAppOnFileThread(
    237     const WebApplicationInfo& web_app) {
    238   scoped_refptr<Extension> extension(ConvertWebAppToExtension(
    239       web_app, base::Time::Now(), install_directory_));
    240   if (!extension.get()) {
    241     // Validation should have stopped any potential errors before getting here.
    242     NOTREACHED() << "Could not convert web app to extension.";
    243     return;
    244   }
    245 
    246   // TODO(aa): conversion data gets lost here :(
    247 
    248   OnUnpackSuccess(extension->path(), extension->path(), NULL, extension.get(),
    249                   SkBitmap());
    250 }
    251 
    252 CrxInstallerError CrxInstaller::AllowInstall(const Extension* extension) {
    253   DCHECK(installer_task_runner_->RunsTasksOnCurrentThread());
    254 
    255   // Make sure the expected ID matches if one was supplied or if we want to
    256   // bypass the prompt.
    257   if ((approved_ || !expected_id_.empty()) &&
    258       expected_id_ != extension->id()) {
    259     return CrxInstallerError(
    260         l10n_util::GetStringFUTF16(IDS_EXTENSION_INSTALL_UNEXPECTED_ID,
    261                                    base::ASCIIToUTF16(expected_id_),
    262                                    base::ASCIIToUTF16(extension->id())));
    263   }
    264 
    265   if (expected_version_.get()) {
    266     if (expected_version_strict_checking_) {
    267       if (!expected_version_->Equals(*extension->version())) {
    268         return CrxInstallerError(
    269             l10n_util::GetStringFUTF16(
    270               IDS_EXTENSION_INSTALL_UNEXPECTED_VERSION,
    271               base::ASCIIToUTF16(expected_version_->GetString()),
    272               base::ASCIIToUTF16(extension->version()->GetString())));
    273       }
    274     } else {
    275       if (extension->version()->CompareTo(*expected_version_) < 0) {
    276         return CrxInstallerError(
    277             l10n_util::GetStringFUTF16(
    278               IDS_EXTENSION_INSTALL_UNEXPECTED_VERSION,
    279               base::ASCIIToUTF16(expected_version_->GetString() + "+"),
    280               base::ASCIIToUTF16(extension->version()->GetString())));
    281       }
    282     }
    283   }
    284 
    285   // Make sure the manifests match if we want to bypass the prompt.
    286   if (approved_) {
    287     bool valid = false;
    288     if (expected_manifest_check_level_ ==
    289         WebstoreInstaller::MANIFEST_CHECK_LEVEL_NONE) {
    290         // To skip manifest checking, the extension must be a shared module
    291         // and not request any permissions.
    292       if (SharedModuleInfo::IsSharedModule(extension) &&
    293           extension->permissions_data()->active_permissions()->IsEmpty()) {
    294           valid = true;
    295         }
    296     } else {
    297       valid = expected_manifest_->Equals(original_manifest_.get());
    298       if (!valid && expected_manifest_check_level_ ==
    299           WebstoreInstaller::MANIFEST_CHECK_LEVEL_LOOSE) {
    300         std::string error;
    301         scoped_refptr<Extension> dummy_extension =
    302             Extension::Create(base::FilePath(),
    303                               install_source_,
    304                               *expected_manifest_->value(),
    305                               creation_flags_,
    306                               &error);
    307         if (error.empty()) {
    308           scoped_refptr<const PermissionSet> expected_permissions =
    309               dummy_extension->permissions_data()->active_permissions();
    310           valid = !(PermissionMessageProvider::Get()->IsPrivilegeIncrease(
    311               expected_permissions,
    312               extension->permissions_data()->active_permissions(),
    313               extension->GetType()));
    314         }
    315       }
    316     }
    317 
    318     if (!valid)
    319       return CrxInstallerError(
    320           l10n_util::GetStringUTF16(IDS_EXTENSION_MANIFEST_INVALID));
    321   }
    322 
    323   // The checks below are skipped for themes and external installs.
    324   // TODO(pamg): After ManagementPolicy refactoring is complete, remove this
    325   // and other uses of install_source_ that are no longer needed now that the
    326   // SandboxedUnpacker sets extension->location.
    327   if (extension->is_theme() || Manifest::IsExternalLocation(install_source_))
    328     return CrxInstallerError();
    329 
    330   if (!extensions_enabled_) {
    331     return CrxInstallerError(
    332         l10n_util::GetStringUTF16(IDS_EXTENSION_INSTALL_NOT_ENABLED));
    333   }
    334 
    335   if (install_cause_ == extension_misc::INSTALL_CAUSE_USER_DOWNLOAD) {
    336     if (FeatureSwitch::easy_off_store_install()->IsEnabled()) {
    337       const char* kHistogramName = "Extensions.OffStoreInstallDecisionEasy";
    338       if (is_gallery_install()) {
    339         UMA_HISTOGRAM_ENUMERATION(kHistogramName, OnStoreInstall,
    340                                   NumOffStoreInstallDecision);
    341       } else {
    342         UMA_HISTOGRAM_ENUMERATION(kHistogramName, OffStoreInstallAllowed,
    343                                   NumOffStoreInstallDecision);
    344       }
    345     } else {
    346       const char* kHistogramName = "Extensions.OffStoreInstallDecisionHard";
    347       if (is_gallery_install()) {
    348         UMA_HISTOGRAM_ENUMERATION(kHistogramName, OnStoreInstall,
    349                                   NumOffStoreInstallDecision);
    350       } else if (off_store_install_allow_reason_ != OffStoreInstallDisallowed) {
    351         UMA_HISTOGRAM_ENUMERATION(kHistogramName, OffStoreInstallAllowed,
    352                                   NumOffStoreInstallDecision);
    353         UMA_HISTOGRAM_ENUMERATION("Extensions.OffStoreInstallAllowReason",
    354                                   off_store_install_allow_reason_,
    355                                   NumOffStoreInstallAllowReasons);
    356       } else {
    357         UMA_HISTOGRAM_ENUMERATION(kHistogramName, OffStoreInstallDisallowed,
    358                                   NumOffStoreInstallDecision);
    359         // Don't delete source in this case so that the user can install
    360         // manually if they want.
    361         delete_source_ = false;
    362         did_handle_successfully_ = false;
    363 
    364         return CrxInstallerError(
    365             CrxInstallerError::ERROR_OFF_STORE,
    366             l10n_util::GetStringUTF16(
    367                 IDS_EXTENSION_INSTALL_DISALLOWED_ON_SITE));
    368       }
    369     }
    370   }
    371 
    372   if (installer_.extension()->is_app()) {
    373     // 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     // right mime type.  Make an exception for file URLs, which come
    376     // from the users computer and have no headers.
    377     if (!download_url_.SchemeIsFile() &&
    378         apps_require_extension_mime_type_ &&
    379         original_mime_type_ != Extension::kMimeType) {
    380       return CrxInstallerError(
    381           l10n_util::GetStringFUTF16(
    382               IDS_EXTENSION_INSTALL_INCORRECT_APP_CONTENT_TYPE,
    383               base::ASCIIToUTF16(Extension::kMimeType)));
    384     }
    385 
    386     // If the client_ is NULL, then the app is either being installed via
    387     // an internal mechanism like sync, external_extensions, or default apps.
    388     // In that case, we don't want to enforce things like the install origin.
    389     if (!is_gallery_install() && client_) {
    390       // For apps with a gallery update URL, require that they be installed
    391       // from the gallery.
    392       // TODO(erikkay) Apply this rule for paid extensions and themes as well.
    393       if (ManifestURL::UpdatesFromGallery(extension)) {
    394         return CrxInstallerError(
    395             l10n_util::GetStringFUTF16(
    396                 IDS_EXTENSION_DISALLOW_NON_DOWNLOADED_GALLERY_INSTALLS,
    397                 l10n_util::GetStringUTF16(IDS_EXTENSION_WEB_STORE_TITLE)));
    398       }
    399 
    400       // 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       // no way for us to verify that the app controls any other hosts.
    403       URLPattern pattern(UserScript::ValidUserScriptSchemes());
    404       pattern.SetHost(download_url_.host());
    405       pattern.SetMatchSubdomains(true);
    406 
    407       URLPatternSet patterns = installer_.extension()->web_extent();
    408       for (URLPatternSet::const_iterator i = patterns.begin();
    409            i != patterns.end(); ++i) {
    410         if (!pattern.MatchesHost(i->host())) {
    411           return CrxInstallerError(
    412               l10n_util::GetStringUTF16(
    413                   IDS_EXTENSION_INSTALL_INCORRECT_INSTALL_HOST));
    414         }
    415       }
    416     }
    417   }
    418 
    419   return CrxInstallerError();
    420 }
    421 
    422 void CrxInstaller::OnUnpackFailure(const base::string16& error_message) {
    423   DCHECK(installer_task_runner_->RunsTasksOnCurrentThread());
    424 
    425   UMA_HISTOGRAM_ENUMERATION("Extensions.UnpackFailureInstallSource",
    426                             install_source(), Manifest::NUM_LOCATIONS);
    427 
    428   UMA_HISTOGRAM_ENUMERATION("Extensions.UnpackFailureInstallCause",
    429                             install_cause(),
    430                             extension_misc::NUM_INSTALL_CAUSES);
    431 
    432   ReportFailureFromFileThread(CrxInstallerError(error_message));
    433 }
    434 
    435 void CrxInstaller::OnUnpackSuccess(
    436     const base::FilePath& temp_dir,
    437     const base::FilePath& extension_dir,
    438     const base::DictionaryValue* original_manifest,
    439     const Extension* extension,
    440     const SkBitmap& install_icon) {
    441   DCHECK(installer_task_runner_->RunsTasksOnCurrentThread());
    442 
    443   UMA_HISTOGRAM_ENUMERATION("Extensions.UnpackSuccessInstallSource",
    444                             install_source(), Manifest::NUM_LOCATIONS);
    445 
    446 
    447   UMA_HISTOGRAM_ENUMERATION("Extensions.UnpackSuccessInstallCause",
    448                             install_cause(),
    449                             extension_misc::NUM_INSTALL_CAUSES);
    450 
    451   installer_.set_extension(extension);
    452   temp_dir_ = temp_dir;
    453   if (!install_icon.empty())
    454     install_icon_.reset(new SkBitmap(install_icon));
    455 
    456   if (original_manifest)
    457     original_manifest_.reset(new Manifest(
    458         Manifest::INVALID_LOCATION,
    459         scoped_ptr<base::DictionaryValue>(original_manifest->DeepCopy())));
    460 
    461   // We don't have to delete the unpack dir explicity since it is a child of
    462   // the temp dir.
    463   unpacked_extension_root_ = extension_dir;
    464 
    465   CrxInstallerError error = AllowInstall(extension);
    466   if (error.type() != CrxInstallerError::ERROR_NONE) {
    467     ReportFailureFromFileThread(error);
    468     return;
    469   }
    470 
    471   if (!BrowserThread::PostTask(
    472         BrowserThread::UI, FROM_HERE,
    473         base::Bind(&CrxInstaller::CheckImportsAndRequirements, this)))
    474     NOTREACHED();
    475 }
    476 
    477 void CrxInstaller::CheckImportsAndRequirements() {
    478   DCHECK_CURRENTLY_ON(BrowserThread::UI);
    479   ExtensionService* service = service_weak_.get();
    480   if (!service || service->browser_terminating())
    481     return;
    482 
    483   if (SharedModuleInfo::ImportsModules(extension())) {
    484     const std::vector<SharedModuleInfo::ImportInfo>& imports =
    485         SharedModuleInfo::GetImports(extension());
    486     std::vector<SharedModuleInfo::ImportInfo>::const_iterator i;
    487     for (i = imports.begin(); i != imports.end(); ++i) {
    488       const Extension* imported_module =
    489           service->GetExtensionById(i->extension_id, true);
    490       if (imported_module &&
    491           !SharedModuleInfo::IsSharedModule(imported_module)) {
    492         ReportFailureFromUIThread(
    493             CrxInstallerError(l10n_util::GetStringFUTF16(
    494                 IDS_EXTENSION_INSTALL_DEPENDENCY_NOT_SHARED_MODULE,
    495                 base::ASCIIToUTF16(i->extension_id))));
    496         return;
    497       } else if (imported_module &&
    498           !SharedModuleInfo::IsExportAllowedByWhitelist(imported_module,
    499                                                         extension()->id())) {
    500         ReportFailureFromUIThread(
    501             CrxInstallerError(l10n_util::GetStringFUTF16(
    502                 IDS_EXTENSION_INSTALL_DEPENDENCY_NOT_WHITELISTED,
    503                 base::ASCIIToUTF16(i->extension_id))));
    504         return;
    505       }
    506     }
    507   }
    508   installer_.CheckRequirements(base::Bind(&CrxInstaller::OnRequirementsChecked,
    509                                           this));
    510 }
    511 
    512 void CrxInstaller::OnRequirementsChecked(
    513     std::vector<std::string> requirement_errors) {
    514   DCHECK_CURRENTLY_ON(BrowserThread::UI);
    515   if (!service_weak_)
    516     return;
    517 
    518   if (!requirement_errors.empty()) {
    519     if (error_on_unsupported_requirements_) {
    520       ReportFailureFromUIThread(CrxInstallerError(
    521           base::UTF8ToUTF16(JoinString(requirement_errors, ' '))));
    522       return;
    523     }
    524     install_flags_ |= kInstallFlagHasRequirementErrors;
    525   }
    526 
    527   ExtensionSystem::Get(profile())->blacklist()->IsBlacklisted(
    528       extension()->id(),
    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;
    540   }
    541 
    542   if ((blacklist_state == extensions::BLACKLISTED_MALWARE ||
    543        blacklist_state == extensions::BLACKLISTED_UNKNOWN) &&
    544       !allow_silent_install_) {
    545     // User tried to install a blacklisted extension. Show an error and
    546     // refuse to install it.
    547     ReportFailureFromUIThread(extensions::CrxInstallerError(
    548         l10n_util::GetStringFUTF16(IDS_EXTENSION_IS_BLACKLISTED,
    549                                    base::UTF8ToUTF16(extension()->name()))));
    550     UMA_HISTOGRAM_ENUMERATION("ExtensionBlacklist.BlockCRX",
    551                               extension()->location(),
    552                               Manifest::NUM_LOCATIONS);
    553     return;
    554   }
    555 
    556   // NOTE: extension may still be blacklisted, but we're forced to silently
    557   // install it. In this case, ExtensionService::OnExtensionInstalled needs to
    558   // deal with it.
    559   ConfirmInstall();
    560 }
    561 
    562 void CrxInstaller::ConfirmInstall() {
    563   DCHECK_CURRENTLY_ON(BrowserThread::UI);
    564   ExtensionService* service = service_weak_.get();
    565   if (!service || service->browser_terminating())
    566     return;
    567 
    568   if (KioskModeInfo::IsKioskOnly(installer_.extension())) {
    569     bool in_kiosk_mode = false;
    570 #if defined(OS_CHROMEOS)
    571     chromeos::UserManager* user_manager = chromeos::UserManager::Get();
    572     in_kiosk_mode = user_manager && user_manager->IsLoggedInAsKioskApp();
    573 #endif
    574     if (!in_kiosk_mode) {
    575       ReportFailureFromUIThread(CrxInstallerError(
    576           l10n_util::GetStringUTF16(
    577               IDS_EXTENSION_INSTALL_KIOSK_MODE_ONLY)));
    578       return;
    579     }
    580   }
    581 
    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
    594   // update an existing extension or app.
    595   CheckUpdateFromSettingsPage();
    596 
    597   GURL overlapping_url;
    598   const Extension* overlapping_extension =
    599       service->extensions()->GetHostedAppByOverlappingWebExtent(
    600           extension()->web_extent());
    601   if (overlapping_extension &&
    602       overlapping_extension->id() != extension()->id()) {
    603     ReportFailureFromUIThread(
    604         CrxInstallerError(
    605             l10n_util::GetStringFUTF16(
    606                 IDS_EXTENSION_OVERLAPPING_WEB_EXTENT,
    607                 base::UTF8ToUTF16(overlapping_extension->name()))));
    608     return;
    609   }
    610 
    611   current_version_ = ExtensionPrefs::Get(service->profile())
    612                          ->GetVersionString(extension()->id());
    613 
    614   if (client_ &&
    615       (!allow_silent_install_ || !approved_) &&
    616       !update_from_settings_page_) {
    617     AddRef();  // Balanced in InstallUIProceed() and InstallUIAbort().
    618     client_->ConfirmInstall(this, extension(), show_dialog_callback_);
    619   } else {
    620     if (!installer_task_runner_->PostTask(
    621             FROM_HERE,
    622             base::Bind(&CrxInstaller::CompleteInstall, this)))
    623       NOTREACHED();
    624   }
    625   return;
    626 }
    627 
    628 void CrxInstaller::InstallUIProceed() {
    629   DCHECK_CURRENTLY_ON(BrowserThread::UI);
    630 
    631   ExtensionService* service = service_weak_.get();
    632   if (!service || service->browser_terminating())
    633     return;
    634 
    635   // If update_from_settings_page_ boolean is true, this functions is
    636   // getting called in response to ExtensionInstallPrompt::ConfirmReEnable()
    637   // and if it is false, this function is called in response to
    638   // ExtensionInstallPrompt::ConfirmInstall().
    639   if (update_from_settings_page_) {
    640     service->GrantPermissionsAndEnableExtension(extension());
    641   } else {
    642     if (!installer_task_runner_->PostTask(
    643             FROM_HERE,
    644             base::Bind(&CrxInstaller::CompleteInstall, this)))
    645       NOTREACHED();
    646   }
    647 
    648   Release();  // balanced in ConfirmInstall() or ConfirmReEnable().
    649 }
    650 
    651 void CrxInstaller::InstallUIAbort(bool user_initiated) {
    652   // If update_from_settings_page_ boolean is true, this functions is
    653   // getting called in response to ExtensionInstallPrompt::ConfirmReEnable()
    654   // and if it is false, this function is called in response to
    655   // ExtensionInstallPrompt::ConfirmInstall().
    656   if (!update_from_settings_page_) {
    657     std::string histogram_name = user_initiated
    658                                      ? "Extensions.Permissions_InstallCancel2"
    659                                      : "Extensions.Permissions_InstallAbort2";
    660     ExtensionService::RecordPermissionMessagesHistogram(
    661         extension(), histogram_name.c_str());
    662 
    663     NotifyCrxInstallComplete(false);
    664   }
    665 
    666   Release();  // balanced in ConfirmInstall() or ConfirmReEnable().
    667 
    668   // We're done. Since we don't post any more tasks to ourself, our ref count
    669   // should go to zero and we die. The destructor will clean up the temp dir.
    670 }
    671 
    672 void CrxInstaller::CompleteInstall() {
    673   DCHECK(installer_task_runner_->RunsTasksOnCurrentThread());
    674 
    675   if (!current_version_.empty()) {
    676     Version current_version(current_version_);
    677     if (current_version.CompareTo(*(extension()->version())) > 0) {
    678       ReportFailureFromFileThread(
    679           CrxInstallerError(
    680               l10n_util::GetStringUTF16(extension()->is_app() ?
    681                   IDS_APP_CANT_DOWNGRADE_VERSION :
    682                   IDS_EXTENSION_CANT_DOWNGRADE_VERSION)));
    683       return;
    684     }
    685   }
    686 
    687   // See how long extension install paths are.  This is important on
    688   // windows, because file operations may fail if the path to a file
    689   // exceeds a small constant.  See crbug.com/69693 .
    690   UMA_HISTOGRAM_CUSTOM_COUNTS(
    691     "Extensions.CrxInstallDirPathLength",
    692         install_directory_.value().length(), 0, 500, 100);
    693 
    694   ExtensionAssetsManager* assets_manager =
    695       ExtensionAssetsManager::GetInstance();
    696   assets_manager->InstallExtension(
    697       extension(),
    698       unpacked_extension_root_,
    699       install_directory_,
    700       profile(),
    701       base::Bind(&CrxInstaller::ReloadExtensionAfterInstall, this));
    702 }
    703 
    704 void CrxInstaller::ReloadExtensionAfterInstall(
    705     const base::FilePath& version_dir) {
    706   DCHECK(installer_task_runner_->RunsTasksOnCurrentThread());
    707 
    708   if (version_dir.empty()) {
    709     ReportFailureFromFileThread(
    710         CrxInstallerError(
    711             l10n_util::GetStringUTF16(
    712                 IDS_EXTENSION_MOVE_DIRECTORY_TO_PROFILE_FAILED)));
    713     return;
    714   }
    715 
    716   // This is lame, but we must reload the extension because absolute paths
    717   // inside the content scripts are established inside InitFromValue() and we
    718   // just moved the extension.
    719   // TODO(aa): All paths to resources inside extensions should be created
    720   // lazily and based on the Extension's root path at that moment.
    721   // TODO(rdevlin.cronin): Continue removing std::string errors and replacing
    722   // with base::string16
    723   std::string extension_id = extension()->id();
    724   std::string error;
    725   installer_.set_extension(
    726       file_util::LoadExtension(
    727           version_dir,
    728           install_source_,
    729           extension()->creation_flags() | Extension::REQUIRE_KEY,
    730           &error).get());
    731 
    732   if (extension()) {
    733     ReportSuccessFromFileThread();
    734   } else {
    735     LOG(ERROR) << error << " " << extension_id << " " << download_url_;
    736     ReportFailureFromFileThread(CrxInstallerError(base::UTF8ToUTF16(error)));
    737   }
    738 }
    739 
    740 void CrxInstaller::ReportFailureFromFileThread(const CrxInstallerError& error) {
    741   DCHECK(installer_task_runner_->RunsTasksOnCurrentThread());
    742   if (!BrowserThread::PostTask(
    743           BrowserThread::UI, FROM_HERE,
    744           base::Bind(&CrxInstaller::ReportFailureFromUIThread, this, error))) {
    745     NOTREACHED();
    746   }
    747 }
    748 
    749 void CrxInstaller::ReportFailureFromUIThread(const CrxInstallerError& error) {
    750   DCHECK_CURRENTLY_ON(BrowserThread::UI);
    751 
    752   if (!service_weak_.get() || service_weak_->browser_terminating())
    753     return;
    754 
    755   content::NotificationService* service =
    756       content::NotificationService::current();
    757   service->Notify(chrome::NOTIFICATION_EXTENSION_INSTALL_ERROR,
    758                   content::Source<CrxInstaller>(this),
    759                   content::Details<const base::string16>(&error.message()));
    760 
    761   // This isn't really necessary, it is only used because unit tests expect to
    762   // see errors get reported via this interface.
    763   //
    764   // TODO(aa): Need to go through unit tests and clean them up too, probably get
    765   // rid of this line.
    766   ExtensionErrorReporter::GetInstance()->ReportError(
    767       error.message(),
    768       false);  // Be quiet.
    769 
    770   if (client_)
    771     client_->OnInstallFailure(error);
    772 
    773   NotifyCrxInstallComplete(false);
    774 
    775   // Delete temporary files.
    776   CleanupTempFiles();
    777 }
    778 
    779 void CrxInstaller::ReportSuccessFromFileThread() {
    780   DCHECK(installer_task_runner_->RunsTasksOnCurrentThread());
    781 
    782   // Tracking number of extensions installed by users
    783   if (install_cause() == extension_misc::INSTALL_CAUSE_USER_DOWNLOAD)
    784     UMA_HISTOGRAM_ENUMERATION("Extensions.ExtensionInstalled", 1, 2);
    785 
    786   if (!BrowserThread::PostTask(
    787           BrowserThread::UI, FROM_HERE,
    788           base::Bind(&CrxInstaller::ReportSuccessFromUIThread, this)))
    789     NOTREACHED();
    790 
    791   // Delete temporary files.
    792   CleanupTempFiles();
    793 }
    794 
    795 void CrxInstaller::ReportSuccessFromUIThread() {
    796   DCHECK_CURRENTLY_ON(BrowserThread::UI);
    797 
    798   if (!service_weak_.get() || service_weak_->browser_terminating())
    799     return;
    800 
    801   if (!update_from_settings_page_) {
    802     // If there is a client, tell the client about installation.
    803     if (client_)
    804       client_->OnInstallSuccess(extension(), install_icon_.get());
    805 
    806     // We update the extension's granted permissions if the user already
    807     // approved the install (client_ is non NULL), or we are allowed to install
    808     // this silently.
    809     if ((client_ || allow_silent_install_) && grant_permissions_) {
    810       PermissionsUpdater perms_updater(profile());
    811       perms_updater.GrantActivePermissions(extension());
    812     }
    813   }
    814 
    815   service_weak_->OnExtensionInstalled(
    816       extension(), page_ordinal_, install_flags_);
    817   NotifyCrxInstallComplete(true);
    818 }
    819 
    820 void CrxInstaller::NotifyCrxInstallBegin() {
    821   InstallTrackerFactory::GetForProfile(profile())
    822       ->OnBeginCrxInstall(expected_id_);
    823 }
    824 
    825 void CrxInstaller::NotifyCrxInstallComplete(bool success) {
    826   // Some users (such as the download shelf) need to know when a
    827   // CRXInstaller is done.  Listening for the EXTENSION_* events
    828   // is problematic because they don't know anything about the
    829   // extension before it is unpacked, so they cannot filter based
    830   // on the extension.
    831   content::NotificationService::current()->Notify(
    832       chrome::NOTIFICATION_CRX_INSTALLER_DONE,
    833       content::Source<CrxInstaller>(this),
    834       content::Details<const Extension>(
    835           success ? extension() : NULL));
    836 
    837   InstallTrackerFactory::GetForProfile(profile())
    838       ->OnFinishCrxInstall(success ? extension()->id() : expected_id_, success);
    839 
    840   if (success)
    841     ConfirmReEnable();
    842 }
    843 
    844 void CrxInstaller::CleanupTempFiles() {
    845   if (!installer_task_runner_->RunsTasksOnCurrentThread()) {
    846     if (!installer_task_runner_->PostTask(
    847             FROM_HERE,
    848             base::Bind(&CrxInstaller::CleanupTempFiles, this))) {
    849       NOTREACHED();
    850     }
    851     return;
    852   }
    853 
    854   // Delete the temp directory and crx file as necessary.
    855   if (!temp_dir_.value().empty()) {
    856     file_util::DeleteFile(temp_dir_, true);
    857     temp_dir_ = base::FilePath();
    858   }
    859 
    860   if (delete_source_ && !source_file_.value().empty()) {
    861     file_util::DeleteFile(source_file_, false);
    862     source_file_ = base::FilePath();
    863   }
    864 }
    865 
    866 void CrxInstaller::CheckUpdateFromSettingsPage() {
    867   DCHECK_CURRENTLY_ON(BrowserThread::UI);
    868 
    869   ExtensionService* service = service_weak_.get();
    870   if (!service || service->browser_terminating())
    871     return;
    872 
    873   if (off_store_install_allow_reason_ != OffStoreInstallAllowedFromSettingsPage)
    874     return;
    875 
    876   const Extension* installed_extension =
    877       service->GetInstalledExtension(extension()->id());
    878   if (installed_extension) {
    879     // Previous version of the extension exists.
    880     update_from_settings_page_ = true;
    881     expected_id_ = installed_extension->id();
    882     install_source_ = installed_extension->location();
    883     install_cause_ = extension_misc::INSTALL_CAUSE_UPDATE;
    884   }
    885 }
    886 
    887 void CrxInstaller::ConfirmReEnable() {
    888   DCHECK_CURRENTLY_ON(BrowserThread::UI);
    889 
    890   ExtensionService* service = service_weak_.get();
    891   if (!service || service->browser_terminating())
    892     return;
    893 
    894   if (!update_from_settings_page_)
    895     return;
    896 
    897   ExtensionPrefs* prefs = ExtensionPrefs::Get(service->profile());
    898   if (!prefs->DidExtensionEscalatePermissions(extension()->id()))
    899     return;
    900 
    901   if (client_) {
    902     AddRef();  // Balanced in InstallUIProceed() and InstallUIAbort().
    903     client_->ConfirmReEnable(this, extension());
    904   }
    905 }
    906 
    907 }  // namespace extensions
    908