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.
5 #ifndef CHROME_BROWSER_EXTENSIONS_CRX_INSTALLER_H_
6 #define CHROME_BROWSER_EXTENSIONS_CRX_INSTALLER_H_
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"
24 class ExtensionService
;
25 class ExtensionServiceTest
;
27 struct WebApplicationInfo
;
30 class SequencedTaskRunner
;
33 namespace extensions
{
34 class CrxInstallerError
;
35 class ExtensionUpdaterTest
;
36 class RequirementsChecker
;
38 // This class installs a crx file into a profile.
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
46 // Lifetime management:
48 // This class is ref-counted by each call it makes to itself on another thread,
49 // and by UtilityProcessHost.
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.
54 // IMPORTANT: Callers should keep a reference to a CrxInstaller while they are
55 // working with it, eg:
57 // scoped_refptr<CrxInstaller> installer(new CrxInstaller(...));
58 // installer->set_foo();
59 // installer->set_bar();
60 // installer->InstallCrx(...);
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.
67 : public SandboxedUnpackerClient
,
68 public ExtensionInstallPrompt::Delegate
{
70 // Used in histograms; do not change order.
71 enum OffStoreInstallAllowReason
{
72 OffStoreInstallDisallowed
,
73 OffStoreInstallAllowedFromSettingsPage
,
74 OffStoreInstallAllowedBecausePref
,
75 OffStoreInstallAllowedInTest
,
76 NumOffStoreInstallAllowReasons
79 // Extensions will be installed into service->install_directory(), then
80 // registered with |service|. This does a silent install - see below for
82 static scoped_refptr
<CrxInstaller
> CreateSilent(ExtensionService
* service
);
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
);
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
);
96 // Install the crx in |source_file|.
97 void InstallCrx(const base::FilePath
& source_file
);
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
);
103 // Convert the specified web app into an extension and install it.
104 void InstallWebApp(const WebApplicationInfo
& web_app
);
106 // Overridden from ExtensionInstallPrompt::Delegate:
107 virtual void InstallUIProceed() OVERRIDE
;
108 virtual void InstallUIAbort(bool user_initiated
) OVERRIDE
;
110 int creation_flags() const { return creation_flags_
; }
111 void set_creation_flags(int val
) { creation_flags_
= val
; }
113 const GURL
& download_url() const { return download_url_
; }
114 void set_download_url(const GURL
& val
) { download_url_
= val
; }
116 const base::FilePath
& source_file() const { return source_file_
; }
118 Manifest::Location
install_source() const {
119 return install_source_
;
121 void set_install_source(Manifest::Location source
) {
122 install_source_
= source
;
125 const std::string
& expected_id() const { return expected_id_
; }
126 void set_expected_id(const std::string
& val
) { expected_id_
= val
; }
128 void set_expected_version(const Version
& val
) {
129 expected_version_
.reset(new Version(val
));
130 expected_version_strict_checking_
= true;
133 bool delete_source() const { return delete_source_
; }
134 void set_delete_source(bool val
) { delete_source_
= val
; }
136 bool allow_silent_install() const { return allow_silent_install_
; }
137 void set_allow_silent_install(bool val
) { allow_silent_install_
= val
; }
139 bool is_gallery_install() const {
140 return (creation_flags_
& Extension::FROM_WEBSTORE
) > 0;
142 void set_is_gallery_install(bool val
) {
144 creation_flags_
|= Extension::FROM_WEBSTORE
;
146 creation_flags_
&= ~Extension::FROM_WEBSTORE
;
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.
152 const GURL
& original_download_url() const { return original_download_url_
; }
153 void set_original_download_url(const GURL
& url
) {
154 original_download_url_
= url
;
157 // If |apps_require_extension_mime_type_| is set to true, be sure to set
158 // |original_mime_type_| as well.
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
;
164 void set_original_mime_type(const std::string
& original_mime_type
) {
165 original_mime_type_
= original_mime_type
;
168 extension_misc::CrxInstallCause
install_cause() const {
169 return install_cause_
;
171 void set_install_cause(extension_misc::CrxInstallCause install_cause
) {
172 install_cause_
= install_cause
;
175 OffStoreInstallAllowReason
off_store_install_allow_reason() const {
176 return off_store_install_allow_reason_
;
178 void set_off_store_install_allow_reason(OffStoreInstallAllowReason reason
) {
179 off_store_install_allow_reason_
= reason
;
182 void set_page_ordinal(const syncer::StringOrdinal
& page_ordinal
) {
183 page_ordinal_
= page_ordinal
;
186 void set_error_on_unsupported_requirements(bool val
) {
187 error_on_unsupported_requirements_
= val
;
190 void set_install_wait_for_idle(bool val
) {
191 install_wait_for_idle_
= val
;
194 bool did_handle_successfully() const { return did_handle_successfully_
; }
196 Profile
* profile() { return installer_
.profile(); }
198 const Extension
* extension() { return installer_
.extension().get(); }
201 friend class ::ExtensionServiceTest
;
202 friend class ExtensionUpdaterTest
;
203 friend class ExtensionCrxInstallerTest
;
205 CrxInstaller(base::WeakPtr
<ExtensionService
> service_weak
,
206 scoped_ptr
<ExtensionInstallPrompt
> client
,
207 const WebstoreInstaller::Approval
* approval
);
208 virtual ~CrxInstaller();
210 // Converts the source user script to an extension.
211 void ConvertUserScriptOnFileThread();
213 // Converts the source web app to an extension.
214 void ConvertWebAppOnFileThread(const WebApplicationInfo
& web_app
,
215 const base::FilePath
& install_directory
);
217 // Called after OnUnpackSuccess as a last check to see whether the install
219 CrxInstallerError
AllowInstall(const Extension
* extension
);
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
;
229 // Called on the UI thread to start the requirements check on the extension.
230 void CheckImportsAndRequirements();
232 // Runs on the UI thread. Callback from RequirementsChecker.
233 void OnRequirementsChecked(std::vector
<std::string
> requirement_errors
);
235 // Runs on the UI thread. Callback from Blacklist.
236 void OnBlacklistChecked(
237 extensions::BlacklistState blacklist_state
);
239 // Runs on the UI thread. Confirms the installation to the ExtensionService.
240 void ConfirmInstall();
242 // Runs on File thread. Install the unpacked extension into the profile and
243 // notify the frontend.
244 void CompleteInstall();
247 void ReportFailureFromFileThread(const CrxInstallerError
& error
);
248 void ReportFailureFromUIThread(const CrxInstallerError
& error
);
249 void ReportSuccessFromFileThread();
250 void ReportSuccessFromUIThread();
251 void NotifyCrxInstallComplete(bool success
);
253 // Deletes temporary directory and crx file if needed.
254 void CleanupTempFiles();
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();
260 // Show re-enable prompt if the update is initiated from the settings page
261 // and needs additional permissions.
262 void ConfirmReEnable();
264 // The file we're installing.
265 base::FilePath source_file_
;
267 // The URL the file was downloaded from.
270 // The directory extensions are installed to.
271 base::FilePath install_directory_
;
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_
;
278 // Indicates whether the user has already approved the extension to be
279 // installed. If true, |expected_manifest_| and |expected_id_| must match
283 // For updates, external and webstore installs we have an ID we're expecting
284 // the extension to contain.
285 std::string expected_id_
;
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_
;
292 // The level of checking when comparing the actual manifest against
293 // the |expected_manifest_|.
294 WebstoreInstaller::ManifestCheckLevel expected_manifest_check_level_
;
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
300 scoped_ptr
<Version
> expected_version_
;
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_
;
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
310 bool extensions_enabled_
;
312 // Whether we're supposed to delete the source file on destruction. Defaults
316 // The download URL, before redirects, if this is a gallery install.
317 GURL original_download_url_
;
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
322 bool create_app_shortcut_
;
324 // The ordinal of the NTP apps page |extension_| will be shown on.
325 syncer::StringOrdinal page_ordinal_
;
327 // A parsed copy of the unmodified original manifest, before any
328 // transformations like localization have taken place.
329 scoped_ptr
<Manifest
> original_manifest_
;
331 // If non-empty, contains the current version of the extension we're
332 // installing (for upgrades).
333 std::string current_version_
;
335 // The icon we will display in the installation UI, if any.
336 scoped_ptr
<SkBitmap
> install_icon_
;
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_
;
342 // The frontend we will report results back to.
343 base::WeakPtr
<ExtensionService
> service_weak_
;
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_
;
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_
;
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_
;
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
362 bool allow_silent_install_
;
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_
;
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_
;
372 // Creation flags to use for the extension. These flags will be used
373 // when calling Extenion::Create() by the crx installer.
376 // Whether to allow off store installation.
377 OffStoreInstallAllowReason off_store_install_allow_reason_
;
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_
;
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_
;
391 bool has_requirement_errors_
;
393 extensions::BlacklistState blacklist_state_
;
395 bool install_wait_for_idle_
;
397 // Sequenced task runner where file I/O operations will be performed.
398 scoped_refptr
<base::SequencedTaskRunner
> installer_task_runner_
;
400 // Used to show the install dialog.
401 ExtensionInstallPrompt::ShowDialogCallback show_dialog_callback_
;
403 // Whether the update is initiated by the user from the extension settings
405 bool update_from_settings_page_
;
407 // Gives access to common methods and data of an extension installer.
408 ExtensionInstaller installer_
;
410 DISALLOW_COPY_AND_ASSIGN(CrxInstaller
);
413 } // namespace extensions
415 #endif // CHROME_BROWSER_EXTENSIONS_CRX_INSTALLER_H_