• 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_CRX_INSTALLER_H_
6 #define CHROME_BROWSER_EXTENSIONS_CRX_INSTALLER_H_
7 
8 #include <string>
9 
10 #include "base/compiler_specific.h"
11 #include "base/files/file_path.h"
12 #include "base/memory/ref_counted.h"
13 #include "base/memory/weak_ptr.h"
14 #include "base/version.h"
15 #include "chrome/browser/extensions/blacklist.h"
16 #include "chrome/browser/extensions/extension_install_prompt.h"
17 #include "chrome/browser/extensions/extension_installer.h"
18 #include "chrome/browser/extensions/sandboxed_unpacker.h"
19 #include "chrome/browser/extensions/webstore_installer.h"
20 #include "extensions/common/extension.h"
21 #include "extensions/common/manifest.h"
22 #include "sync/api/string_ordinal.h"
23 
24 class ExtensionService;
25 class ExtensionServiceTest;
26 class SkBitmap;
27 struct WebApplicationInfo;
28 
29 namespace base {
30 class SequencedTaskRunner;
31 }
32 
33 namespace extensions {
34 class CrxInstallerError;
35 class ExtensionUpdaterTest;
36 class RequirementsChecker;
37 
38 // This class installs a crx file into a profile.
39 //
40 // Installing a CRX is a multi-step process, including unpacking the crx,
41 // validating it, prompting the user, and installing. Since many of these
42 // steps must occur on the file thread, this class contains a copy of all data
43 // necessary to do its job. (This also minimizes external dependencies for
44 // easier testing).
45 //
46 // Lifetime management:
47 //
48 // This class is ref-counted by each call it makes to itself on another thread,
49 // and by UtilityProcessHost.
50 //
51 // Additionally, we hold a reference to our own client so that it lives at least
52 // long enough to receive the result of unpacking.
53 //
54 // IMPORTANT: Callers should keep a reference to a CrxInstaller while they are
55 // working with it, eg:
56 //
57 // scoped_refptr<CrxInstaller> installer(new CrxInstaller(...));
58 // installer->set_foo();
59 // installer->set_bar();
60 // installer->InstallCrx(...);
61 //
62 // Installation is aborted if the extension service learns that Chrome is
63 // terminating during the install. We can't listen for the app termination
64 // notification here in this class because it can be destroyed on any thread
65 // and won't safely be able to clean up UI thread notification listeners.
66 class CrxInstaller
67     : public SandboxedUnpackerClient,
68       public ExtensionInstallPrompt::Delegate {
69  public:
70   // Used in histograms; do not change order.
71   enum OffStoreInstallAllowReason {
72     OffStoreInstallDisallowed,
73     OffStoreInstallAllowedFromSettingsPage,
74     OffStoreInstallAllowedBecausePref,
75     OffStoreInstallAllowedInTest,
76     NumOffStoreInstallAllowReasons
77   };
78 
79   // Extensions will be installed into service->install_directory(), then
80   // registered with |service|. This does a silent install - see below for
81   // other options.
82   static scoped_refptr<CrxInstaller> CreateSilent(ExtensionService* service);
83 
84   // Same as above, but use |client| to generate a confirmation prompt.
85   static scoped_refptr<CrxInstaller> Create(
86       ExtensionService* service,
87       scoped_ptr<ExtensionInstallPrompt> client);
88 
89   // Same as the previous method, except use the |approval| to bypass the
90   // prompt. Note that the caller retains ownership of |approval|.
91   static scoped_refptr<CrxInstaller> Create(
92       ExtensionService* service,
93       scoped_ptr<ExtensionInstallPrompt> client,
94       const WebstoreInstaller::Approval* approval);
95 
96   // Install the crx in |source_file|.
97   void InstallCrx(const base::FilePath& source_file);
98 
99   // Convert the specified user script into an extension and install it.
100   void InstallUserScript(const base::FilePath& source_file,
101                          const GURL& download_url);
102 
103   // Convert the specified web app into an extension and install it.
104   void InstallWebApp(const WebApplicationInfo& web_app);
105 
106   // Overridden from ExtensionInstallPrompt::Delegate:
107   virtual void InstallUIProceed() OVERRIDE;
108   virtual void InstallUIAbort(bool user_initiated) OVERRIDE;
109 
creation_flags()110   int creation_flags() const { return creation_flags_; }
set_creation_flags(int val)111   void set_creation_flags(int val) { creation_flags_ = val; }
112 
download_url()113   const GURL& download_url() const { return download_url_; }
set_download_url(const GURL & val)114   void set_download_url(const GURL& val) { download_url_ = val; }
115 
source_file()116   const base::FilePath& source_file() const { return source_file_; }
117 
install_source()118   Manifest::Location install_source() const {
119     return install_source_;
120   }
set_install_source(Manifest::Location source)121   void set_install_source(Manifest::Location source) {
122     install_source_ = source;
123   }
124 
expected_id()125   const std::string& expected_id() const { return expected_id_; }
set_expected_id(const std::string & val)126   void set_expected_id(const std::string& val) { expected_id_ = val; }
127 
set_expected_version(const Version & val)128   void set_expected_version(const Version& val) {
129     expected_version_.reset(new Version(val));
130     expected_version_strict_checking_ = true;
131   }
132 
delete_source()133   bool delete_source() const { return delete_source_; }
set_delete_source(bool val)134   void set_delete_source(bool val) { delete_source_ = val; }
135 
allow_silent_install()136   bool allow_silent_install() const { return allow_silent_install_; }
set_allow_silent_install(bool val)137   void set_allow_silent_install(bool val) { allow_silent_install_ = val; }
138 
is_gallery_install()139   bool is_gallery_install() const {
140     return (creation_flags_ & Extension::FROM_WEBSTORE) > 0;
141   }
set_is_gallery_install(bool val)142   void set_is_gallery_install(bool val) {
143     if (val)
144       creation_flags_ |= Extension::FROM_WEBSTORE;
145     else
146       creation_flags_ &= ~Extension::FROM_WEBSTORE;
147   }
148 
149   // The original download URL should be set when the WebstoreInstaller is
150   // tracking the installation. The WebstoreInstaller uses this URL to match
151   // failure notifications to the extension.
original_download_url()152   const GURL& original_download_url() const { return original_download_url_; }
set_original_download_url(const GURL & url)153   void set_original_download_url(const GURL& url) {
154     original_download_url_ = url;
155   }
156 
157   // If |apps_require_extension_mime_type_| is set to true, be sure to set
158   // |original_mime_type_| as well.
set_apps_require_extension_mime_type(bool apps_require_extension_mime_type)159   void set_apps_require_extension_mime_type(
160       bool apps_require_extension_mime_type) {
161     apps_require_extension_mime_type_ = apps_require_extension_mime_type;
162   }
163 
set_original_mime_type(const std::string & original_mime_type)164   void set_original_mime_type(const std::string& original_mime_type) {
165     original_mime_type_ = original_mime_type;
166   }
167 
install_cause()168   extension_misc::CrxInstallCause install_cause() const {
169     return install_cause_;
170   }
set_install_cause(extension_misc::CrxInstallCause install_cause)171   void set_install_cause(extension_misc::CrxInstallCause install_cause) {
172     install_cause_ = install_cause;
173   }
174 
off_store_install_allow_reason()175   OffStoreInstallAllowReason off_store_install_allow_reason() const {
176     return off_store_install_allow_reason_;
177   }
set_off_store_install_allow_reason(OffStoreInstallAllowReason reason)178   void set_off_store_install_allow_reason(OffStoreInstallAllowReason reason) {
179     off_store_install_allow_reason_ = reason;
180   }
181 
set_page_ordinal(const syncer::StringOrdinal & page_ordinal)182   void set_page_ordinal(const syncer::StringOrdinal& page_ordinal) {
183     page_ordinal_ = page_ordinal;
184   }
185 
set_error_on_unsupported_requirements(bool val)186   void set_error_on_unsupported_requirements(bool val) {
187     error_on_unsupported_requirements_ = val;
188   }
189 
set_install_wait_for_idle(bool val)190   void set_install_wait_for_idle(bool val) {
191     install_wait_for_idle_ = val;
192   }
193 
did_handle_successfully()194   bool did_handle_successfully() const { return did_handle_successfully_; }
195 
profile()196   Profile* profile() { return installer_.profile(); }
197 
extension()198   const Extension* extension() { return installer_.extension().get(); }
199 
200  private:
201   friend class ::ExtensionServiceTest;
202   friend class ExtensionUpdaterTest;
203   friend class ExtensionCrxInstallerTest;
204 
205   CrxInstaller(base::WeakPtr<ExtensionService> service_weak,
206                scoped_ptr<ExtensionInstallPrompt> client,
207                const WebstoreInstaller::Approval* approval);
208   virtual ~CrxInstaller();
209 
210   // Converts the source user script to an extension.
211   void ConvertUserScriptOnFileThread();
212 
213   // Converts the source web app to an extension.
214   void ConvertWebAppOnFileThread(const WebApplicationInfo& web_app,
215                                  const base::FilePath& install_directory);
216 
217   // Called after OnUnpackSuccess as a last check to see whether the install
218   // should complete.
219   CrxInstallerError AllowInstall(const Extension* extension);
220 
221   // SandboxedUnpackerClient
222   virtual void OnUnpackFailure(const base::string16& error_message) OVERRIDE;
223   virtual void OnUnpackSuccess(const base::FilePath& temp_dir,
224                                const base::FilePath& extension_dir,
225                                const base::DictionaryValue* original_manifest,
226                                const Extension* extension,
227                                const SkBitmap& install_icon) OVERRIDE;
228 
229   // Called on the UI thread to start the requirements check on the extension.
230   void CheckImportsAndRequirements();
231 
232   // Runs on the UI thread. Callback from RequirementsChecker.
233   void OnRequirementsChecked(std::vector<std::string> requirement_errors);
234 
235   // Runs on the UI thread. Callback from Blacklist.
236   void OnBlacklistChecked(
237       extensions::Blacklist::BlacklistState blacklist_state);
238 
239   // Runs on the UI thread. Confirms the installation to the ExtensionService.
240   void ConfirmInstall();
241 
242   // Runs on File thread. Install the unpacked extension into the profile and
243   // notify the frontend.
244   void CompleteInstall();
245 
246   // Result reporting.
247   void ReportFailureFromFileThread(const CrxInstallerError& error);
248   void ReportFailureFromUIThread(const CrxInstallerError& error);
249   void ReportSuccessFromFileThread();
250   void ReportSuccessFromUIThread();
251   void NotifyCrxInstallComplete(bool success);
252 
253   // Deletes temporary directory and crx file if needed.
254   void CleanupTempFiles();
255 
256   // Checks whether the current installation is initiated by the user from
257   // the extension settings page to update an existing extension or app.
258   void CheckUpdateFromSettingsPage();
259 
260   // Show re-enable prompt if the update is initiated from the settings page
261   // and needs additional permissions.
262   void ConfirmReEnable();
263 
264   // The file we're installing.
265   base::FilePath source_file_;
266 
267   // The URL the file was downloaded from.
268   GURL download_url_;
269 
270   // The directory extensions are installed to.
271   base::FilePath install_directory_;
272 
273   // The location the installation came from (bundled with Chromium, registry,
274   // manual install, etc). This metadata is saved with the installation if
275   // successful. Defaults to INTERNAL.
276   Manifest::Location install_source_;
277 
278   // Indicates whether the user has already approved the extension to be
279   // installed. If true, |expected_manifest_| and |expected_id_| must match
280   // those of the CRX.
281   bool approved_;
282 
283   // For updates, external and webstore installs we have an ID we're expecting
284   // the extension to contain.
285   std::string expected_id_;
286 
287   // A parsed copy of the expected manifest, before any transformations like
288   // localization have taken place. If |approved_| is true, then the
289   // extension's manifest must match this for the install to proceed.
290   scoped_ptr<Manifest> expected_manifest_;
291 
292   // The level of checking when comparing the actual manifest against
293   // the |expected_manifest_|.
294   WebstoreInstaller::ManifestCheckLevel expected_manifest_check_level_;
295 
296   // If non-NULL, contains the expected version of the extension we're
297   // installing.  Important for external sources, where claiming the wrong
298   // version could cause unnecessary unpacking of an extension at every
299   // restart.
300   scoped_ptr<Version> expected_version_;
301 
302   // If true, the actual version should be same with the |expected_version_|,
303   // Otherwise the actual version should be equal to or newer than
304   // the |expected_version_|.
305   bool expected_version_strict_checking_;
306 
307   // Whether manual extension installation is enabled. We can't just check this
308   // before trying to install because themes are special-cased to always be
309   // allowed.
310   bool extensions_enabled_;
311 
312   // Whether we're supposed to delete the source file on destruction. Defaults
313   // to false.
314   bool delete_source_;
315 
316   // The download URL, before redirects, if this is a gallery install.
317   GURL original_download_url_;
318 
319   // Whether to create an app shortcut after successful installation. This is
320   // set based on the user's selection in the UI and can only ever be true for
321   // apps.
322   bool create_app_shortcut_;
323 
324   // The ordinal of the NTP apps page |extension_| will be shown on.
325   syncer::StringOrdinal page_ordinal_;
326 
327   // A parsed copy of the unmodified original manifest, before any
328   // transformations like localization have taken place.
329   scoped_ptr<Manifest> original_manifest_;
330 
331   // If non-empty, contains the current version of the extension we're
332   // installing (for upgrades).
333   std::string current_version_;
334 
335   // The icon we will display in the installation UI, if any.
336   scoped_ptr<SkBitmap> install_icon_;
337 
338   // The temp directory extension resources were unpacked to. We own this and
339   // must delete it when we are done with it.
340   base::FilePath temp_dir_;
341 
342   // The frontend we will report results back to.
343   base::WeakPtr<ExtensionService> service_weak_;
344 
345   // The client we will work with to do the installation. This can be NULL, in
346   // which case the install is silent.
347   // NOTE: we may be deleted on the file thread. To ensure the UI is deleted on
348   // the main thread we don't use a scoped_ptr here.
349   ExtensionInstallPrompt* client_;
350 
351   // The root of the unpacked extension directory. This is a subdirectory of
352   // temp_dir_, so we don't have to delete it explicitly.
353   base::FilePath unpacked_extension_root_;
354 
355   // True when the CRX being installed was just downloaded.
356   // Used to trigger extra checks before installing.
357   bool apps_require_extension_mime_type_;
358 
359   // Allows for the possibility of a normal install (one in which a |client|
360   // is provided in the ctor) to procede without showing the permissions prompt
361   // dialog.
362   bool allow_silent_install_;
363 
364   // The value of the content type header sent with the CRX.
365   // Ignorred unless |require_extension_mime_type_| is true.
366   std::string original_mime_type_;
367 
368   // What caused this install?  Used only for histograms that report
369   // on failure rates, broken down by the cause of the install.
370   extension_misc::CrxInstallCause install_cause_;
371 
372   // Creation flags to use for the extension.  These flags will be used
373   // when calling Extenion::Create() by the crx installer.
374   int creation_flags_;
375 
376   // Whether to allow off store installation.
377   OffStoreInstallAllowReason off_store_install_allow_reason_;
378 
379   // Whether the installation was handled successfully. This is used to
380   // indicate to the client whether the file should be removed and any UI
381   // initiating the installation can be removed. This is different than whether
382   // there was an error; if there was an error that rejects installation we
383   // still consider the installation 'handled'.
384   bool did_handle_successfully_;
385 
386   // Whether we should produce an error if the manifest declares requirements
387   // that are not met. If false and there is an unmet requirement, the install
388   // will continue but the extension will be distabled.
389   bool error_on_unsupported_requirements_;
390 
391   bool has_requirement_errors_;
392 
393   extensions::Blacklist::BlacklistState blacklist_state_;
394 
395   bool install_wait_for_idle_;
396 
397   // Sequenced task runner where file I/O operations will be performed.
398   scoped_refptr<base::SequencedTaskRunner> installer_task_runner_;
399 
400   // Used to show the install dialog.
401   ExtensionInstallPrompt::ShowDialogCallback show_dialog_callback_;
402 
403   // Whether the update is initiated by the user from the extension settings
404   // page.
405   bool update_from_settings_page_;
406 
407   // Gives access to common methods and data of an extension installer.
408   ExtensionInstaller installer_;
409 
410   DISALLOW_COPY_AND_ASSIGN(CrxInstaller);
411 };
412 
413 }  // namespace extensions
414 
415 #endif  // CHROME_BROWSER_EXTENSIONS_CRX_INSTALLER_H_
416