root/chrome/browser/extensions/webstore_installer.h

/* [<][>][^][v][top][bottom][index][help] */

INCLUDED FROM


// 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/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/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 Extension;
class Manifest;

// Downloads and installs extensions from the web store.
class WebstoreInstaller : public content::NotificationObserver,
                          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);

    virtual ~Approval();

    // 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 (experimental) are not permanently installed in Chrome.
    bool is_ephemeral;

   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
  virtual void Observe(int type,
                       const content::NotificationSource& source,
                       const content::NotificationDetails& details) 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>;
  virtual ~WebstoreInstaller();

  // 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:
  virtual void OnDownloadUpdated(content::DownloadItem* download) OVERRIDE;
  virtual 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();

  // 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_;
  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_;

  // 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_

/* [<][>][^][v][top][bottom][index][help] */