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_WEBSTORE_INSTALLER_H_
      6 #define CHROME_BROWSER_EXTENSIONS_WEBSTORE_INSTALLER_H_
      7 
      8 #include <list>
      9 #include <string>
     10 
     11 #include "base/compiler_specific.h"
     12 #include "base/memory/ref_counted.h"
     13 #include "base/memory/scoped_ptr.h"
     14 #include "base/supports_user_data.h"
     15 #include "base/values.h"
     16 #include "base/version.h"
     17 #include "chrome/browser/extensions/extension_install_prompt.h"
     18 #include "content/public/browser/browser_thread.h"
     19 #include "content/public/browser/download_item.h"
     20 #include "content/public/browser/notification_observer.h"
     21 #include "content/public/browser/notification_registrar.h"
     22 #include "extensions/common/manifest_handlers/shared_module_info.h"
     23 #include "net/base/net_errors.h"
     24 #include "ui/gfx/image/image_skia.h"
     25 #include "url/gurl.h"
     26 
     27 class Profile;
     28 
     29 namespace base {
     30 class FilePath;
     31 }
     32 
     33 namespace content {
     34 class NavigationController;
     35 }
     36 
     37 namespace extensions {
     38 
     39 class Extension;
     40 class Manifest;
     41 
     42 // Downloads and installs extensions from the web store.
     43 class WebstoreInstaller :public content::NotificationObserver,
     44                          public content::DownloadItem::Observer,
     45                          public base::RefCountedThreadSafe<
     46   WebstoreInstaller, content::BrowserThread::DeleteOnUIThread> {
     47  public:
     48   enum InstallSource {
     49     // Inline installs trigger slightly different behavior (install source
     50     // is different, download referrers are the item's page in the gallery).
     51     INSTALL_SOURCE_INLINE,
     52     INSTALL_SOURCE_APP_LAUNCHER,
     53     INSTALL_SOURCE_OTHER
     54   };
     55 
     56   enum FailureReason {
     57     FAILURE_REASON_CANCELLED,
     58     FAILURE_REASON_DEPENDENCY_NOT_FOUND,
     59     FAILURE_REASON_DEPENDENCY_NOT_SHARED_MODULE,
     60     FAILURE_REASON_OTHER
     61   };
     62 
     63   enum ManifestCheckLevel {
     64     // Do not check for any manifest equality.
     65     MANIFEST_CHECK_LEVEL_NONE,
     66 
     67     // Only check that the expected and actual permissions have the same
     68     // effective permissions.
     69     MANIFEST_CHECK_LEVEL_LOOSE,
     70 
     71     // All data in the expected and actual manifests must match.
     72     MANIFEST_CHECK_LEVEL_STRICT,
     73   };
     74 
     75   class Delegate {
     76    public:
     77     virtual void OnExtensionDownloadStarted(const std::string& id,
     78                                             content::DownloadItem* item);
     79     virtual void OnExtensionDownloadProgress(const std::string& id,
     80                                              content::DownloadItem* item);
     81     virtual void OnExtensionInstallSuccess(const std::string& id) = 0;
     82     virtual void OnExtensionInstallFailure(const std::string& id,
     83                                            const std::string& error,
     84                                            FailureReason reason) = 0;
     85 
     86    protected:
     87     virtual ~Delegate() {}
     88   };
     89 
     90   // Contains information about what parts of the extension install process can
     91   // be skipped or modified. If one of these is present, it means that a CRX
     92   // download was initiated by WebstoreInstaller. The Approval instance should
     93   // be checked further for additional details.
     94   struct Approval : public base::SupportsUserData::Data {
     95     static scoped_ptr<Approval> CreateWithInstallPrompt(Profile* profile);
     96 
     97     // Creates an Approval for installing a shared module.
     98     static scoped_ptr<Approval> CreateForSharedModule(Profile* profile);
     99 
    100     // Creates an Approval that will skip putting up an install confirmation
    101     // prompt if the actual manifest from the extension to be installed matches
    102     // |parsed_manifest|. The |strict_manifest_check| controls whether we want
    103     // to require an exact manifest match, or are willing to tolerate a looser
    104     // check just that the effective permissions are the same.
    105     static scoped_ptr<Approval> CreateWithNoInstallPrompt(
    106         Profile* profile,
    107         const std::string& extension_id,
    108         scoped_ptr<base::DictionaryValue> parsed_manifest,
    109         bool strict_manifest_check);
    110 
    111     virtual ~Approval();
    112 
    113     // The extension id that was approved for installation.
    114     std::string extension_id;
    115 
    116     // The profile the extension should be installed into.
    117     Profile* profile;
    118 
    119     // The expected manifest, before localization.
    120     scoped_ptr<Manifest> manifest;
    121 
    122     // Whether to use a bubble notification when an app is installed, instead of
    123     // the default behavior of transitioning to the new tab page.
    124     bool use_app_installed_bubble;
    125 
    126     // Whether to skip the post install UI like the extension installed bubble.
    127     bool skip_post_install_ui;
    128 
    129     // Whether to skip the install dialog once the extension has been downloaded
    130     // and unpacked. One reason this can be true is that in the normal webstore
    131     // installation, the dialog is shown earlier, before any download is done,
    132     // so there's no need to show it again.
    133     bool skip_install_dialog;
    134 
    135     // Whether we should enable the launcher before installing the app.
    136     bool enable_launcher;
    137 
    138     // Manifest check level for checking actual manifest against expected
    139     // manifest.
    140     ManifestCheckLevel manifest_check_level;
    141 
    142     // Used to show the install dialog.
    143     ExtensionInstallPrompt::ShowDialogCallback show_dialog_callback;
    144 
    145     // The icon to use to display the extension while it is installing.
    146     gfx::ImageSkia installing_icon;
    147 
    148     // A dummy extension created from |manifest|;
    149     scoped_refptr<Extension> dummy_extension;
    150 
    151     // Required minimum version.
    152     scoped_ptr<Version> minimum_version;
    153 
    154     // Ephemeral apps (experimental) are not permanently installed in Chrome.
    155     bool is_ephemeral;
    156 
    157    private:
    158     Approval();
    159   };
    160 
    161   // Gets the Approval associated with the |download|, or NULL if there's none.
    162   // Note that the Approval is owned by |download|.
    163   static const Approval* GetAssociatedApproval(
    164       const content::DownloadItem& download);
    165 
    166   // Creates a WebstoreInstaller for downloading and installing the extension
    167   // with the given |id| from the Chrome Web Store. If |delegate| is not NULL,
    168   // it will be notified when the install succeeds or fails. The installer will
    169   // use the specified |controller| to download the extension. Only one
    170   // WebstoreInstaller can use a specific controller at any given time. This
    171   // also associates the |approval| with this install.
    172   // Note: the delegate should stay alive until being called back.
    173   WebstoreInstaller(Profile* profile,
    174                     Delegate* delegate,
    175                     content::NavigationController* controller,
    176                     const std::string& id,
    177                     scoped_ptr<Approval> approval,
    178                     InstallSource source);
    179 
    180   // Starts downloading and installing the extension.
    181   void Start();
    182 
    183   // content::NotificationObserver
    184   virtual void Observe(int type,
    185                        const content::NotificationSource& source,
    186                        const content::NotificationDetails& details) OVERRIDE;
    187 
    188   // Removes the reference to the delegate passed in the constructor. Used when
    189   // the delegate object must be deleted before this object.
    190   void InvalidateDelegate();
    191 
    192   // Instead of using the default download directory, use |directory| instead.
    193   // This does *not* transfer ownership of |directory|.
    194   static void SetDownloadDirectoryForTests(base::FilePath* directory);
    195 
    196  private:
    197   FRIEND_TEST_ALL_PREFIXES(WebstoreInstallerTest, PlatformParams);
    198   friend struct content::BrowserThread::DeleteOnThread<
    199    content::BrowserThread::UI>;
    200   friend class base::DeleteHelper<WebstoreInstaller>;
    201   virtual ~WebstoreInstaller();
    202 
    203   // Helper to get install URL.
    204   static GURL GetWebstoreInstallURL(const std::string& extension_id,
    205                                     InstallSource source);
    206 
    207   // DownloadManager::DownloadUrl callback.
    208   void OnDownloadStarted(content::DownloadItem* item, net::Error error);
    209 
    210   // DownloadItem::Observer implementation:
    211   virtual void OnDownloadUpdated(content::DownloadItem* download) OVERRIDE;
    212   virtual void OnDownloadDestroyed(content::DownloadItem* download) OVERRIDE;
    213 
    214   // Downloads next pending module in |pending_modules_|.
    215   void DownloadNextPendingModule();
    216 
    217   // Downloads and installs a single Crx with the given |extension_id|.
    218   // This function is used for both the extension Crx and dependences.
    219   void DownloadCrx(const std::string& extension_id, InstallSource source);
    220 
    221   // Starts downloading the extension to |file_path|.
    222   void StartDownload(const base::FilePath& file_path);
    223 
    224   // Reports an install |error| to the delegate for the given extension if this
    225   // managed its installation. This also removes the associated PendingInstall.
    226   void ReportFailure(const std::string& error, FailureReason reason);
    227 
    228   // Reports a successful install to the delegate for the given extension if
    229   // this managed its installation. This also removes the associated
    230   // PendingInstall.
    231   void ReportSuccess();
    232 
    233   // Records stats regarding an interrupted webstore download item.
    234   void RecordInterrupt(const content::DownloadItem* download) const;
    235 
    236   content::NotificationRegistrar registrar_;
    237   Profile* profile_;
    238   Delegate* delegate_;
    239   content::NavigationController* controller_;
    240   std::string id_;
    241   InstallSource install_source_;
    242   // The DownloadItem is owned by the DownloadManager and is valid from when
    243   // OnDownloadStarted is called (with no error) until OnDownloadDestroyed().
    244   content::DownloadItem* download_item_;
    245   scoped_ptr<Approval> approval_;
    246   GURL download_url_;
    247 
    248   // Pending modules.
    249   std::list<SharedModuleInfo::ImportInfo> pending_modules_;
    250   // Total extension modules we need download and install (the main module and
    251   // depedences).
    252   int total_modules_;
    253   bool download_started_;
    254 };
    255 
    256 }  // namespace extensions
    257 
    258 #endif  // CHROME_BROWSER_EXTENSIONS_WEBSTORE_INSTALLER_H_
    259