• 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/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:
~Delegate()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) OVERRIDE;
204 
205   // Removes the reference to the delegate passed in the constructor. Used when
206   // the delegate object must be deleted before this object.
207   void InvalidateDelegate();
208 
209   // Instead of using the default download directory, use |directory| instead.
210   // This does *not* transfer ownership of |directory|.
211   static void SetDownloadDirectoryForTests(base::FilePath* directory);
212 
213  private:
214   FRIEND_TEST_ALL_PREFIXES(WebstoreInstallerTest, PlatformParams);
215   friend struct content::BrowserThread::DeleteOnThread<
216    content::BrowserThread::UI>;
217   friend class base::DeleteHelper<WebstoreInstaller>;
218   virtual ~WebstoreInstaller();
219 
220   // Helper to get install URL.
221   static GURL GetWebstoreInstallURL(const std::string& extension_id,
222                                     InstallSource source);
223 
224   // DownloadManager::DownloadUrl callback.
225   void OnDownloadStarted(content::DownloadItem* item,
226                          content::DownloadInterruptReason interrupt_reason);
227 
228   // DownloadItem::Observer implementation:
229   virtual void OnDownloadUpdated(content::DownloadItem* download) OVERRIDE;
230   virtual void OnDownloadDestroyed(content::DownloadItem* download) OVERRIDE;
231 
232   // Downloads next pending module in |pending_modules_|.
233   void DownloadNextPendingModule();
234 
235   // Downloads and installs a single Crx with the given |extension_id|.
236   // This function is used for both the extension Crx and dependences.
237   void DownloadCrx(const std::string& extension_id, InstallSource source);
238 
239   // Starts downloading the extension to |file_path|.
240   void StartDownload(const base::FilePath& file_path);
241 
242   // Updates the InstallTracker with the latest download progress.
243   void UpdateDownloadProgress();
244 
245   // Creates and starts CrxInstaller for the downloaded extension package.
246   void StartCrxInstaller(const content::DownloadItem& item);
247 
248   // Reports an install |error| to the delegate for the given extension if this
249   // managed its installation. This also removes the associated PendingInstall.
250   void ReportFailure(const std::string& error, FailureReason reason);
251 
252   // Reports a successful install to the delegate for the given extension if
253   // this managed its installation. This also removes the associated
254   // PendingInstall.
255   void ReportSuccess();
256 
257   // Records stats regarding an interrupted webstore download item.
258   void RecordInterrupt(const content::DownloadItem* download) const;
259 
260   content::NotificationRegistrar registrar_;
261   ScopedObserver<ExtensionRegistry, ExtensionRegistryObserver>
262       extension_registry_observer_;
263   Profile* profile_;
264   Delegate* delegate_;
265   std::string id_;
266   InstallSource install_source_;
267   // The DownloadItem is owned by the DownloadManager and is valid from when
268   // OnDownloadStarted is called (with no error) until OnDownloadDestroyed().
269   content::DownloadItem* download_item_;
270   // Used to periodically update the extension's download status. This will
271   // trigger at least every second, though sometimes more frequently (depending
272   // on number of modules, etc).
273   base::OneShotTimer<WebstoreInstaller> download_progress_timer_;
274   scoped_ptr<Approval> approval_;
275   GURL download_url_;
276   scoped_refptr<CrxInstaller> crx_installer_;
277 
278   // Pending modules.
279   std::list<SharedModuleInfo::ImportInfo> pending_modules_;
280   // Total extension modules we need download and install (the main module and
281   // depedences).
282   int total_modules_;
283   bool download_started_;
284 };
285 
286 }  // namespace extensions
287 
288 #endif  // CHROME_BROWSER_EXTENSIONS_WEBSTORE_INSTALLER_H_
289