| // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef CHROME_BROWSER_EXTENSIONS_WEBSTORE_INSTALLER_H_ |
| #define CHROME_BROWSER_EXTENSIONS_WEBSTORE_INSTALLER_H_ |
| |
| #include <list> |
| #include <string> |
| |
| #include "base/compiler_specific.h" |
| #include "base/memory/ref_counted.h" |
| #include "base/memory/scoped_ptr.h" |
| #include "base/scoped_observer.h" |
| #include "base/supports_user_data.h" |
| #include "base/timer/timer.h" |
| #include "base/values.h" |
| #include "base/version.h" |
| #include "chrome/browser/extensions/extension_install_prompt.h" |
| #include "content/public/browser/browser_thread.h" |
| #include "content/public/browser/download_interrupt_reasons.h" |
| #include "content/public/browser/download_item.h" |
| #include "content/public/browser/notification_observer.h" |
| #include "content/public/browser/notification_registrar.h" |
| #include "content/public/browser/web_contents_observer.h" |
| #include "extensions/browser/extension_registry_observer.h" |
| #include "extensions/common/manifest_handlers/shared_module_info.h" |
| #include "ui/gfx/image/image_skia.h" |
| #include "url/gurl.h" |
| |
| class Profile; |
| |
| namespace base { |
| class FilePath; |
| } |
| |
| namespace content { |
| class WebContents; |
| } |
| |
| namespace extensions { |
| |
| class CrxInstaller; |
| class Extension; |
| class ExtensionRegistry; |
| class Manifest; |
| |
| // Downloads and installs extensions from the web store. |
| class WebstoreInstaller : public content::NotificationObserver, |
| public ExtensionRegistryObserver, |
| public content::DownloadItem::Observer, |
| public content::WebContentsObserver, |
| public base::RefCountedThreadSafe< |
| WebstoreInstaller, |
| content::BrowserThread::DeleteOnUIThread> { |
| public: |
| enum InstallSource { |
| // Inline installs trigger slightly different behavior (install source |
| // is different, download referrers are the item's page in the gallery). |
| INSTALL_SOURCE_INLINE, |
| INSTALL_SOURCE_APP_LAUNCHER, |
| INSTALL_SOURCE_OTHER |
| }; |
| |
| enum FailureReason { |
| FAILURE_REASON_CANCELLED, |
| FAILURE_REASON_DEPENDENCY_NOT_FOUND, |
| FAILURE_REASON_DEPENDENCY_NOT_SHARED_MODULE, |
| FAILURE_REASON_OTHER |
| }; |
| |
| enum ManifestCheckLevel { |
| // Do not check for any manifest equality. |
| MANIFEST_CHECK_LEVEL_NONE, |
| |
| // Only check that the expected and actual permissions have the same |
| // effective permissions. |
| MANIFEST_CHECK_LEVEL_LOOSE, |
| |
| // All data in the expected and actual manifests must match. |
| MANIFEST_CHECK_LEVEL_STRICT, |
| }; |
| |
| class Delegate { |
| public: |
| virtual void OnExtensionDownloadStarted(const std::string& id, |
| content::DownloadItem* item); |
| virtual void OnExtensionDownloadProgress(const std::string& id, |
| content::DownloadItem* item); |
| virtual void OnExtensionInstallSuccess(const std::string& id) = 0; |
| virtual void OnExtensionInstallFailure(const std::string& id, |
| const std::string& error, |
| FailureReason reason) = 0; |
| |
| protected: |
| virtual ~Delegate() {} |
| }; |
| |
| // Contains information about what parts of the extension install process can |
| // be skipped or modified. If one of these is present, it means that a CRX |
| // download was initiated by WebstoreInstaller. The Approval instance should |
| // be checked further for additional details. |
| struct Approval : public base::SupportsUserData::Data { |
| static scoped_ptr<Approval> CreateWithInstallPrompt(Profile* profile); |
| |
| // Creates an Approval for installing a shared module. |
| static scoped_ptr<Approval> CreateForSharedModule(Profile* profile); |
| |
| // Creates an Approval that will skip putting up an install confirmation |
| // prompt if the actual manifest from the extension to be installed matches |
| // |parsed_manifest|. The |strict_manifest_check| controls whether we want |
| // to require an exact manifest match, or are willing to tolerate a looser |
| // check just that the effective permissions are the same. |
| static scoped_ptr<Approval> CreateWithNoInstallPrompt( |
| Profile* profile, |
| const std::string& extension_id, |
| scoped_ptr<base::DictionaryValue> parsed_manifest, |
| bool strict_manifest_check); |
| |
| ~Approval() override; |
| |
| // The extension id that was approved for installation. |
| std::string extension_id; |
| |
| // The profile the extension should be installed into. |
| Profile* profile; |
| |
| // The expected manifest, before localization. |
| scoped_ptr<Manifest> manifest; |
| |
| // Whether to use a bubble notification when an app is installed, instead of |
| // the default behavior of transitioning to the new tab page. |
| bool use_app_installed_bubble; |
| |
| // Whether to skip the post install UI like the extension installed bubble. |
| bool skip_post_install_ui; |
| |
| // Whether to skip the install dialog once the extension has been downloaded |
| // and unpacked. One reason this can be true is that in the normal webstore |
| // installation, the dialog is shown earlier, before any download is done, |
| // so there's no need to show it again. |
| bool skip_install_dialog; |
| |
| // Whether we should enable the launcher before installing the app. |
| bool enable_launcher; |
| |
| // Manifest check level for checking actual manifest against expected |
| // manifest. |
| ManifestCheckLevel manifest_check_level; |
| |
| // Used to show the install dialog. |
| ExtensionInstallPrompt::ShowDialogCallback show_dialog_callback; |
| |
| // The icon to use to display the extension while it is installing. |
| gfx::ImageSkia installing_icon; |
| |
| // A dummy extension created from |manifest|; |
| scoped_refptr<Extension> dummy_extension; |
| |
| // Required minimum version. |
| scoped_ptr<Version> minimum_version; |
| |
| // Ephemeral apps are transiently installed. |
| bool is_ephemeral; |
| |
| // The authuser index required to download the item being installed. May be |
| // the empty string, in which case no authuser parameter is used. |
| std::string authuser; |
| |
| private: |
| Approval(); |
| }; |
| |
| // Gets the Approval associated with the |download|, or NULL if there's none. |
| // Note that the Approval is owned by |download|. |
| static const Approval* GetAssociatedApproval( |
| const content::DownloadItem& download); |
| |
| // Creates a WebstoreInstaller for downloading and installing the extension |
| // with the given |id| from the Chrome Web Store. If |delegate| is not NULL, |
| // it will be notified when the install succeeds or fails. The installer will |
| // use the specified |controller| to download the extension. Only one |
| // WebstoreInstaller can use a specific controller at any given time. This |
| // also associates the |approval| with this install. |
| // Note: the delegate should stay alive until being called back. |
| WebstoreInstaller(Profile* profile, |
| Delegate* delegate, |
| content::WebContents* web_contents, |
| const std::string& id, |
| scoped_ptr<Approval> approval, |
| InstallSource source); |
| |
| // Starts downloading and installing the extension. |
| void Start(); |
| |
| // content::NotificationObserver. |
| void Observe(int type, |
| const content::NotificationSource& source, |
| const content::NotificationDetails& details) override; |
| |
| // ExtensionRegistryObserver. |
| void OnExtensionInstalled(content::BrowserContext* browser_context, |
| const Extension* extension, |
| bool is_update) override; |
| |
| // Removes the reference to the delegate passed in the constructor. Used when |
| // the delegate object must be deleted before this object. |
| void InvalidateDelegate(); |
| |
| // Instead of using the default download directory, use |directory| instead. |
| // This does *not* transfer ownership of |directory|. |
| static void SetDownloadDirectoryForTests(base::FilePath* directory); |
| |
| private: |
| FRIEND_TEST_ALL_PREFIXES(WebstoreInstallerTest, PlatformParams); |
| friend struct content::BrowserThread::DeleteOnThread< |
| content::BrowserThread::UI>; |
| friend class base::DeleteHelper<WebstoreInstaller>; |
| ~WebstoreInstaller() override; |
| |
| // Helper to get install URL. |
| static GURL GetWebstoreInstallURL(const std::string& extension_id, |
| InstallSource source); |
| |
| // DownloadManager::DownloadUrl callback. |
| void OnDownloadStarted(content::DownloadItem* item, |
| content::DownloadInterruptReason interrupt_reason); |
| |
| // DownloadItem::Observer implementation: |
| void OnDownloadUpdated(content::DownloadItem* download) override; |
| void OnDownloadDestroyed(content::DownloadItem* download) override; |
| |
| // Downloads next pending module in |pending_modules_|. |
| void DownloadNextPendingModule(); |
| |
| // Downloads and installs a single Crx with the given |extension_id|. |
| // This function is used for both the extension Crx and dependences. |
| void DownloadCrx(const std::string& extension_id, InstallSource source); |
| |
| // Starts downloading the extension to |file_path|. |
| void StartDownload(const base::FilePath& file_path); |
| |
| // Updates the InstallTracker with the latest download progress. |
| void UpdateDownloadProgress(); |
| |
| // Creates and starts CrxInstaller for the downloaded extension package. |
| void StartCrxInstaller(const content::DownloadItem& item); |
| |
| // Reports an install |error| to the delegate for the given extension if this |
| // managed its installation. This also removes the associated PendingInstall. |
| void ReportFailure(const std::string& error, FailureReason reason); |
| |
| // Reports a successful install to the delegate for the given extension if |
| // this managed its installation. This also removes the associated |
| // PendingInstall. |
| void ReportSuccess(); |
| |
| // Records stats regarding an interrupted webstore download item. |
| void RecordInterrupt(const content::DownloadItem* download) const; |
| |
| content::NotificationRegistrar registrar_; |
| ScopedObserver<ExtensionRegistry, ExtensionRegistryObserver> |
| extension_registry_observer_; |
| Profile* profile_; |
| Delegate* delegate_; |
| std::string id_; |
| InstallSource install_source_; |
| // The DownloadItem is owned by the DownloadManager and is valid from when |
| // OnDownloadStarted is called (with no error) until OnDownloadDestroyed(). |
| content::DownloadItem* download_item_; |
| // Used to periodically update the extension's download status. This will |
| // trigger at least every second, though sometimes more frequently (depending |
| // on number of modules, etc). |
| base::OneShotTimer<WebstoreInstaller> download_progress_timer_; |
| scoped_ptr<Approval> approval_; |
| GURL download_url_; |
| scoped_refptr<CrxInstaller> crx_installer_; |
| |
| // Pending modules. |
| std::list<SharedModuleInfo::ImportInfo> pending_modules_; |
| // Total extension modules we need download and install (the main module and |
| // depedences). |
| int total_modules_; |
| bool download_started_; |
| }; |
| |
| } // namespace extensions |
| |
| #endif // CHROME_BROWSER_EXTENSIONS_WEBSTORE_INSTALLER_H_ |