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 #ifndef CHROME_BROWSER_EXTENSIONS_CRX_INSTALLER_H_
      6 #define CHROME_BROWSER_EXTENSIONS_CRX_INSTALLER_H_
      7 
      8 #include <string>
      9 
     10 #include "base/compiler_specific.h"
     11 #include "base/files/file_path.h"
     12 #include "base/memory/ref_counted.h"
     13 #include "base/memory/weak_ptr.h"
     14 #include "base/version.h"
     15 #include "chrome/browser/extensions/blacklist.h"
     16 #include "chrome/browser/extensions/extension_install_prompt.h"
     17 #include "chrome/browser/extensions/extension_installer.h"
     18 #include "chrome/browser/extensions/sandboxed_unpacker.h"
     19 #include "chrome/browser/extensions/webstore_installer.h"
     20 #include "chrome/common/extensions/extension.h"
     21 #include "chrome/common/extensions/manifest.h"
     22 #include "sync/api/string_ordinal.h"
     23 
     24 class ExtensionService;
     25 class ExtensionServiceTest;
     26 class SkBitmap;
     27 struct WebApplicationInfo;
     28 
     29 namespace base {
     30 class SequencedTaskRunner;
     31 }
     32 
     33 namespace extensions {
     34 class CrxInstallerError;
     35 class ExtensionUpdaterTest;
     36 class RequirementsChecker;
     37 
     38 // This class installs a crx file into a profile.
     39 //
     40 // Installing a CRX is a multi-step process, including unpacking the crx,
     41 // validating it, prompting the user, and installing. Since many of these
     42 // steps must occur on the file thread, this class contains a copy of all data
     43 // necessary to do its job. (This also minimizes external dependencies for
     44 // easier testing).
     45 //
     46 // Lifetime management:
     47 //
     48 // This class is ref-counted by each call it makes to itself on another thread,
     49 // and by UtilityProcessHost.
     50 //
     51 // Additionally, we hold a reference to our own client so that it lives at least
     52 // long enough to receive the result of unpacking.
     53 //
     54 // IMPORTANT: Callers should keep a reference to a CrxInstaller while they are
     55 // working with it, eg:
     56 //
     57 // scoped_refptr<CrxInstaller> installer(new CrxInstaller(...));
     58 // installer->set_foo();
     59 // installer->set_bar();
     60 // installer->InstallCrx(...);
     61 //
     62 // Installation is aborted if the extension service learns that Chrome is
     63 // terminating during the install. We can't listen for the app termination
     64 // notification here in this class because it can be destroyed on any thread
     65 // and won't safely be able to clean up UI thread notification listeners.
     66 class CrxInstaller
     67     : public SandboxedUnpackerClient,
     68       public ExtensionInstallPrompt::Delegate {
     69  public:
     70   // Used in histograms; do not change order.
     71   enum OffStoreInstallAllowReason {
     72     OffStoreInstallDisallowed,
     73     OffStoreInstallAllowedFromSettingsPage,
     74     OffStoreInstallAllowedBecausePref,
     75     OffStoreInstallAllowedInTest,
     76     NumOffStoreInstallAllowReasons
     77   };
     78 
     79   // Extensions will be installed into service->install_directory(), then
     80   // registered with |service|. This does a silent install - see below for
     81   // other options.
     82   static scoped_refptr<CrxInstaller> CreateSilent(ExtensionService* service);
     83 
     84   // Same as above, but use |client| to generate a confirmation prompt.
     85   static scoped_refptr<CrxInstaller> Create(
     86       ExtensionService* service,
     87       scoped_ptr<ExtensionInstallPrompt> client);
     88 
     89   // Same as the previous method, except use the |approval| to bypass the
     90   // prompt. Note that the caller retains ownership of |approval|.
     91   static scoped_refptr<CrxInstaller> Create(
     92       ExtensionService* service,
     93       scoped_ptr<ExtensionInstallPrompt> client,
     94       const WebstoreInstaller::Approval* approval);
     95 
     96   // Install the crx in |source_file|.
     97   void InstallCrx(const base::FilePath& source_file);
     98 
     99   // Convert the specified user script into an extension and install it.
    100   void InstallUserScript(const base::FilePath& source_file,
    101                          const GURL& download_url);
    102 
    103   // Convert the specified web app into an extension and install it.
    104   void InstallWebApp(const WebApplicationInfo& web_app);
    105 
    106   // Overridden from ExtensionInstallPrompt::Delegate:
    107   virtual void InstallUIProceed() OVERRIDE;
    108   virtual void InstallUIAbort(bool user_initiated) OVERRIDE;
    109 
    110   int creation_flags() const { return creation_flags_; }
    111   void set_creation_flags(int val) { creation_flags_ = val; }
    112 
    113   const GURL& download_url() const { return download_url_; }
    114   void set_download_url(const GURL& val) { download_url_ = val; }
    115 
    116   const base::FilePath& source_file() const { return source_file_; }
    117 
    118   Manifest::Location install_source() const {
    119     return install_source_;
    120   }
    121   void set_install_source(Manifest::Location source) {
    122     install_source_ = source;
    123   }
    124 
    125   const std::string& expected_id() const { return expected_id_; }
    126   void set_expected_id(const std::string& val) { expected_id_ = val; }
    127 
    128   void set_expected_version(const Version& val) {
    129     expected_version_.reset(new Version(val));
    130   }
    131 
    132   bool delete_source() const { return delete_source_; }
    133   void set_delete_source(bool val) { delete_source_ = val; }
    134 
    135   bool allow_silent_install() const { return allow_silent_install_; }
    136   void set_allow_silent_install(bool val) { allow_silent_install_ = val; }
    137 
    138   bool is_gallery_install() const {
    139     return (creation_flags_ & Extension::FROM_WEBSTORE) > 0;
    140   }
    141   void set_is_gallery_install(bool val) {
    142     if (val)
    143       creation_flags_ |= Extension::FROM_WEBSTORE;
    144     else
    145       creation_flags_ &= ~Extension::FROM_WEBSTORE;
    146   }
    147 
    148   // The original download URL should be set when the WebstoreInstaller is
    149   // tracking the installation. The WebstoreInstaller uses this URL to match
    150   // failure notifications to the extension.
    151   const GURL& original_download_url() const { return original_download_url_; }
    152   void set_original_download_url(const GURL& url) {
    153     original_download_url_ = url;
    154   }
    155 
    156   // If |apps_require_extension_mime_type_| is set to true, be sure to set
    157   // |original_mime_type_| as well.
    158   void set_apps_require_extension_mime_type(
    159       bool apps_require_extension_mime_type) {
    160     apps_require_extension_mime_type_ = apps_require_extension_mime_type;
    161   }
    162 
    163   void set_original_mime_type(const std::string& original_mime_type) {
    164     original_mime_type_ = original_mime_type;
    165   }
    166 
    167   extension_misc::CrxInstallCause install_cause() const {
    168     return install_cause_;
    169   }
    170   void set_install_cause(extension_misc::CrxInstallCause install_cause) {
    171     install_cause_ = install_cause;
    172   }
    173 
    174   OffStoreInstallAllowReason off_store_install_allow_reason() const {
    175     return off_store_install_allow_reason_;
    176   }
    177   void set_off_store_install_allow_reason(OffStoreInstallAllowReason reason) {
    178     off_store_install_allow_reason_ = reason;
    179   }
    180 
    181   void set_page_ordinal(const syncer::StringOrdinal& page_ordinal) {
    182     page_ordinal_ = page_ordinal;
    183   }
    184 
    185   void set_error_on_unsupported_requirements(bool val) {
    186     error_on_unsupported_requirements_ = val;
    187   }
    188 
    189   void set_install_wait_for_idle(bool val) {
    190     install_wait_for_idle_ = val;
    191   }
    192 
    193   bool did_handle_successfully() const { return did_handle_successfully_; }
    194 
    195   Profile* profile() { return installer_.profile(); }
    196 
    197   const Extension* extension() { return installer_.extension().get(); }
    198 
    199  private:
    200   friend class ::ExtensionServiceTest;
    201   friend class ExtensionUpdaterTest;
    202   friend class ExtensionCrxInstallerTest;
    203 
    204   CrxInstaller(base::WeakPtr<ExtensionService> service_weak,
    205                scoped_ptr<ExtensionInstallPrompt> client,
    206                const WebstoreInstaller::Approval* approval);
    207   virtual ~CrxInstaller();
    208 
    209   // Converts the source user script to an extension.
    210   void ConvertUserScriptOnFileThread();
    211 
    212   // Converts the source web app to an extension.
    213   void ConvertWebAppOnFileThread(const WebApplicationInfo& web_app,
    214                                  const base::FilePath& install_directory);
    215 
    216   // Called after OnUnpackSuccess as a last check to see whether the install
    217   // should complete.
    218   CrxInstallerError AllowInstall(const Extension* extension);
    219 
    220   // SandboxedUnpackerClient
    221   virtual void OnUnpackFailure(const string16& error_message) OVERRIDE;
    222   virtual void OnUnpackSuccess(const base::FilePath& temp_dir,
    223                                const base::FilePath& extension_dir,
    224                                const base::DictionaryValue* original_manifest,
    225                                const Extension* extension,
    226                                const SkBitmap& install_icon) OVERRIDE;
    227 
    228   // Called on the UI thread to start the requirements check on the extension.
    229   void CheckImportsAndRequirements();
    230 
    231   // Runs on the UI thread. Callback from RequirementsChecker.
    232   void OnRequirementsChecked(std::vector<std::string> requirement_errors);
    233 
    234   // Runs on the UI thread. Callback from Blacklist.
    235   void OnBlacklistChecked(
    236       extensions::Blacklist::BlacklistState blacklist_state);
    237 
    238   // Runs on the UI thread. Confirms the installation to the ExtensionService.
    239   void ConfirmInstall();
    240 
    241   // Runs on File thread. Install the unpacked extension into the profile and
    242   // notify the frontend.
    243   void CompleteInstall();
    244 
    245   // Result reporting.
    246   void ReportFailureFromFileThread(const CrxInstallerError& error);
    247   void ReportFailureFromUIThread(const CrxInstallerError& error);
    248   void ReportSuccessFromFileThread();
    249   void ReportSuccessFromUIThread();
    250   void NotifyCrxInstallComplete(bool success);
    251 
    252   // Deletes temporary directory and crx file if needed.
    253   void CleanupTempFiles();
    254 
    255   // Checks whether the current installation is initiated by the user from
    256   // the extension settings page to update an existing extension or app.
    257   void CheckUpdateFromSettingsPage();
    258 
    259   // Show re-enable prompt if the update is initiated from the settings page
    260   // and needs additional permissions.
    261   void ConfirmReEnable();
    262 
    263   // The file we're installing.
    264   base::FilePath source_file_;
    265 
    266   // The URL the file was downloaded from.
    267   GURL download_url_;
    268 
    269   // The directory extensions are installed to.
    270   base::FilePath install_directory_;
    271 
    272   // The location the installation came from (bundled with Chromium, registry,
    273   // manual install, etc). This metadata is saved with the installation if
    274   // successful. Defaults to INTERNAL.
    275   Manifest::Location install_source_;
    276 
    277   // Indicates whether the user has already approved the extension to be
    278   // installed. If true, |expected_manifest_| and |expected_id_| must match
    279   // those of the CRX.
    280   bool approved_;
    281 
    282   // For updates, external and webstore installs we have an ID we're expecting
    283   // the extension to contain.
    284   std::string expected_id_;
    285 
    286   // A parsed copy of the expected manifest, before any transformations like
    287   // localization have taken place. If |approved_| is true, then the
    288   // extension's manifest must match this for the install to proceed.
    289   scoped_ptr<Manifest> expected_manifest_;
    290 
    291   // If non-NULL, contains the expected version of the extension we're
    292   // installing.  Important for external sources, where claiming the wrong
    293   // version could cause unnecessary unpacking of an extension at every
    294   // restart.
    295   scoped_ptr<Version> expected_version_;
    296 
    297   // Whether manual extension installation is enabled. We can't just check this
    298   // before trying to install because themes are special-cased to always be
    299   // allowed.
    300   bool extensions_enabled_;
    301 
    302   // Whether we're supposed to delete the source file on destruction. Defaults
    303   // to false.
    304   bool delete_source_;
    305 
    306   // The download URL, before redirects, if this is a gallery install.
    307   GURL original_download_url_;
    308 
    309   // Whether to create an app shortcut after successful installation. This is
    310   // set based on the user's selection in the UI and can only ever be true for
    311   // apps.
    312   bool create_app_shortcut_;
    313 
    314   // The ordinal of the NTP apps page |extension_| will be shown on.
    315   syncer::StringOrdinal page_ordinal_;
    316 
    317   // A parsed copy of the unmodified original manifest, before any
    318   // transformations like localization have taken place.
    319   scoped_ptr<Manifest> original_manifest_;
    320 
    321   // If non-empty, contains the current version of the extension we're
    322   // installing (for upgrades).
    323   std::string current_version_;
    324 
    325   // The icon we will display in the installation UI, if any.
    326   scoped_ptr<SkBitmap> install_icon_;
    327 
    328   // The temp directory extension resources were unpacked to. We own this and
    329   // must delete it when we are done with it.
    330   base::FilePath temp_dir_;
    331 
    332   // The frontend we will report results back to.
    333   base::WeakPtr<ExtensionService> service_weak_;
    334 
    335   // The client we will work with to do the installation. This can be NULL, in
    336   // which case the install is silent.
    337   // NOTE: we may be deleted on the file thread. To ensure the UI is deleted on
    338   // the main thread we don't use a scoped_ptr here.
    339   ExtensionInstallPrompt* client_;
    340 
    341   // The root of the unpacked extension directory. This is a subdirectory of
    342   // temp_dir_, so we don't have to delete it explicitly.
    343   base::FilePath unpacked_extension_root_;
    344 
    345   // True when the CRX being installed was just downloaded.
    346   // Used to trigger extra checks before installing.
    347   bool apps_require_extension_mime_type_;
    348 
    349   // Allows for the possibility of a normal install (one in which a |client|
    350   // is provided in the ctor) to procede without showing the permissions prompt
    351   // dialog.
    352   bool allow_silent_install_;
    353 
    354   // The value of the content type header sent with the CRX.
    355   // Ignorred unless |require_extension_mime_type_| is true.
    356   std::string original_mime_type_;
    357 
    358   // What caused this install?  Used only for histograms that report
    359   // on failure rates, broken down by the cause of the install.
    360   extension_misc::CrxInstallCause install_cause_;
    361 
    362   // Creation flags to use for the extension.  These flags will be used
    363   // when calling Extenion::Create() by the crx installer.
    364   int creation_flags_;
    365 
    366   // Whether to allow off store installation.
    367   OffStoreInstallAllowReason off_store_install_allow_reason_;
    368 
    369   // Whether the installation was handled successfully. This is used to
    370   // indicate to the client whether the file should be removed and any UI
    371   // initiating the installation can be removed. This is different than whether
    372   // there was an error; if there was an error that rejects installation we
    373   // still consider the installation 'handled'.
    374   bool did_handle_successfully_;
    375 
    376   // Whether we should produce an error if the manifest declares requirements
    377   // that are not met. If false and there is an unmet requirement, the install
    378   // will continue but the extension will be distabled.
    379   bool error_on_unsupported_requirements_;
    380 
    381   bool has_requirement_errors_;
    382 
    383   extensions::Blacklist::BlacklistState blacklist_state_;
    384 
    385   bool install_wait_for_idle_;
    386 
    387   // Sequenced task runner where file I/O operations will be performed.
    388   scoped_refptr<base::SequencedTaskRunner> installer_task_runner_;
    389 
    390   // Used to show the install dialog.
    391   ExtensionInstallPrompt::ShowDialogCallback show_dialog_callback_;
    392 
    393   // Whether the update is initiated by the user from the extension settings
    394   // page.
    395   bool update_from_settings_page_;
    396 
    397   // Gives access to common methods and data of an extension installer.
    398   ExtensionInstaller installer_;
    399 
    400   DISALLOW_COPY_AND_ASSIGN(CrxInstaller);
    401 };
    402 
    403 }  // namespace extensions
    404 
    405 #endif  // CHROME_BROWSER_EXTENSIONS_CRX_INSTALLER_H_
    406