• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
~Delegate()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