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