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