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_
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/extension_install_checker.h"
17 #include "chrome/browser/extensions/extension_install_prompt.h"
18 #include "chrome/browser/extensions/extension_service.h"
19 #include "chrome/browser/extensions/webstore_installer.h"
20 #include "chrome/common/extensions/extension_constants.h"
21 #include "extensions/browser/install_flag.h"
22 #include "extensions/browser/sandboxed_unpacker.h"
23 #include "extensions/common/extension.h"
24 #include "extensions/common/manifest.h"
25 #include "sync/api/string_ordinal.h"
27 class ExtensionService
;
28 class ExtensionServiceTest
;
30 struct WebApplicationInfo
;
33 class SequencedTaskRunner
;
36 namespace extensions
{
37 class CrxInstallError
;
38 class ExtensionUpdaterTest
;
39 class RequirementsChecker
;
41 // This class installs a crx file into a profile.
43 // Installing a CRX is a multi-step process, including unpacking the crx,
44 // validating it, prompting the user, and installing. Since many of these
45 // steps must occur on the file thread, this class contains a copy of all data
46 // necessary to do its job. (This also minimizes external dependencies for
49 // Lifetime management:
51 // This class is ref-counted by each call it makes to itself on another thread,
52 // and by UtilityProcessHost.
54 // Additionally, we hold a reference to our own client so that it lives at least
55 // long enough to receive the result of unpacking.
57 // IMPORTANT: Callers should keep a reference to a CrxInstaller while they are
58 // working with it, eg:
60 // scoped_refptr<CrxInstaller> installer(new CrxInstaller(...));
61 // installer->set_foo();
62 // installer->set_bar();
63 // installer->InstallCrx(...);
65 // Installation is aborted if the extension service learns that Chrome is
66 // terminating during the install. We can't listen for the app termination
67 // notification here in this class because it can be destroyed on any thread
68 // and won't safely be able to clean up UI thread notification listeners.
70 : public SandboxedUnpackerClient
,
71 public ExtensionInstallPrompt::Delegate
{
73 // Used in histograms; do not change order.
74 enum OffStoreInstallAllowReason
{
75 OffStoreInstallDisallowed
,
76 OffStoreInstallAllowedFromSettingsPage
,
77 OffStoreInstallAllowedBecausePref
,
78 OffStoreInstallAllowedInTest
,
79 NumOffStoreInstallAllowReasons
82 // Extensions will be installed into service->install_directory(), then
83 // registered with |service|. This does a silent install - see below for
85 static scoped_refptr
<CrxInstaller
> CreateSilent(ExtensionService
* service
);
87 // Same as above, but use |client| to generate a confirmation prompt.
88 static scoped_refptr
<CrxInstaller
> Create(
89 ExtensionService
* service
,
90 scoped_ptr
<ExtensionInstallPrompt
> client
);
92 // Same as the previous method, except use the |approval| to bypass the
93 // prompt. Note that the caller retains ownership of |approval|.
94 static scoped_refptr
<CrxInstaller
> Create(
95 ExtensionService
* service
,
96 scoped_ptr
<ExtensionInstallPrompt
> client
,
97 const WebstoreInstaller::Approval
* approval
);
99 // Install the crx in |source_file|.
100 void InstallCrx(const base::FilePath
& source_file
);
101 void InstallCrxFile(const CRXFileInfo
& source_file
);
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
);
107 // Convert the specified web app into an extension and install it.
108 void InstallWebApp(const WebApplicationInfo
& web_app
);
110 // Overridden from ExtensionInstallPrompt::Delegate:
111 void InstallUIProceed() override
;
112 void InstallUIAbort(bool user_initiated
) override
;
114 int creation_flags() const { return creation_flags_
; }
115 void set_creation_flags(int val
) { creation_flags_
= val
; }
117 const base::FilePath
& source_file() const { return source_file_
; }
119 Manifest::Location
install_source() const {
120 return install_source_
;
122 void set_install_source(Manifest::Location source
) {
123 install_source_
= source
;
126 const std::string
& expected_id() const { return expected_id_
; }
127 void set_expected_id(const std::string
& val
) { expected_id_
= val
; }
129 // Expected SHA256 hash sum for the package.
130 const std::string
& expected_hash() const { return expected_hash_
; }
131 void set_expected_hash(const std::string
& val
) { expected_hash_
= val
; }
133 bool hash_check_failed() const { return hash_check_failed_
; }
134 void set_hash_check_failed(bool val
) { hash_check_failed_
= val
; }
136 // Set the exact version the installed extension should have. If
137 // |fail_install_if_unexpected| is true, installation will fail if the actual
138 // version doesn't match. If it is false, the installation will still
139 // be performed, but the extension will not be granted any permissions.
140 void set_expected_version(const base::Version
& val
,
141 bool fail_install_if_unexpected
) {
142 expected_version_
= val
;
143 fail_install_if_unexpected_version_
= fail_install_if_unexpected
;
146 bool delete_source() const { return delete_source_
; }
147 void set_delete_source(bool val
) { delete_source_
= val
; }
149 bool allow_silent_install() const { return allow_silent_install_
; }
150 void set_allow_silent_install(bool val
) { allow_silent_install_
= val
; }
152 bool grant_permissions() const { return grant_permissions_
; }
153 void set_grant_permissions(bool val
) { grant_permissions_
= val
; }
155 bool is_gallery_install() const {
156 return (creation_flags_
& Extension::FROM_WEBSTORE
) > 0;
158 void set_is_gallery_install(bool val
) {
160 creation_flags_
|= Extension::FROM_WEBSTORE
;
162 creation_flags_
&= ~Extension::FROM_WEBSTORE
;
165 // If |apps_require_extension_mime_type_| is set to true, be sure to set
166 // |original_mime_type_| as well.
167 void set_apps_require_extension_mime_type(
168 bool apps_require_extension_mime_type
) {
169 apps_require_extension_mime_type_
= apps_require_extension_mime_type
;
172 void set_original_mime_type(const std::string
& original_mime_type
) {
173 original_mime_type_
= original_mime_type
;
176 extension_misc::CrxInstallCause
install_cause() const {
177 return install_cause_
;
179 void set_install_cause(extension_misc::CrxInstallCause install_cause
) {
180 install_cause_
= install_cause
;
183 OffStoreInstallAllowReason
off_store_install_allow_reason() const {
184 return off_store_install_allow_reason_
;
186 void set_off_store_install_allow_reason(OffStoreInstallAllowReason reason
) {
187 off_store_install_allow_reason_
= reason
;
190 void set_page_ordinal(const syncer::StringOrdinal
& page_ordinal
) {
191 page_ordinal_
= page_ordinal
;
194 void set_error_on_unsupported_requirements(bool val
) {
195 error_on_unsupported_requirements_
= val
;
198 void set_install_immediately(bool val
) {
199 set_install_flag(kInstallFlagInstallImmediately
, val
);
201 void set_is_ephemeral(bool val
) {
202 set_install_flag(kInstallFlagIsEphemeral
, val
);
204 void set_do_not_sync(bool val
) {
205 set_install_flag(kInstallFlagDoNotSync
, val
);
208 bool did_handle_successfully() const { return did_handle_successfully_
; }
210 Profile
* profile() { return install_checker_
.profile(); }
212 const Extension
* extension() { return install_checker_
.extension().get(); }
214 // The currently installed version of the extension, for updates. Will be
215 // invalid if this isn't an update.
216 const base::Version
& current_version() const { return current_version_
; }
219 friend class ::ExtensionServiceTest
;
220 friend class ExtensionUpdaterTest
;
221 friend class ExtensionCrxInstallerTest
;
223 CrxInstaller(base::WeakPtr
<ExtensionService
> service_weak
,
224 scoped_ptr
<ExtensionInstallPrompt
> client
,
225 const WebstoreInstaller::Approval
* approval
);
226 ~CrxInstaller() override
;
228 // Converts the source user script to an extension.
229 void ConvertUserScriptOnFileThread();
231 // Converts the source web app to an extension.
232 void ConvertWebAppOnFileThread(const WebApplicationInfo
& web_app
);
234 // Called after OnUnpackSuccess as a last check to see whether the install
236 CrxInstallError
AllowInstall(const Extension
* extension
);
238 // SandboxedUnpackerClient
239 void OnUnpackFailure(const CrxInstallError
& error
) override
;
240 void OnUnpackSuccess(const base::FilePath
& temp_dir
,
241 const base::FilePath
& extension_dir
,
242 const base::DictionaryValue
* original_manifest
,
243 const Extension
* extension
,
244 const SkBitmap
& install_icon
) override
;
246 // Called on the UI thread to start the requirements, policy and blacklist
247 // checks on the extension.
250 // Runs on the UI thread. Callback from ExtensionInstallChecker.
251 void OnInstallChecksComplete(int failed_checks
);
253 // Runs on the UI thread. Callback from Blacklist.
254 void OnBlacklistChecked(
255 extensions::BlacklistState blacklist_state
);
257 // Runs on the UI thread. Confirms the installation to the ExtensionService.
258 void ConfirmInstall();
260 // Runs on File thread. Install the unpacked extension into the profile and
261 // notify the frontend.
262 void CompleteInstall();
264 // Reloads extension on File thread and reports installation result back
266 void ReloadExtensionAfterInstall(const base::FilePath
& version_dir
);
269 void ReportFailureFromFileThread(const CrxInstallError
& error
);
270 void ReportFailureFromUIThread(const CrxInstallError
& error
);
271 void ReportSuccessFromFileThread();
272 void ReportSuccessFromUIThread();
273 void NotifyCrxInstallBegin();
274 void NotifyCrxInstallComplete(bool success
);
276 // Deletes temporary directory and crx file if needed.
277 void CleanupTempFiles();
279 // Checks whether the current installation is initiated by the user from
280 // the extension settings page to update an existing extension or app.
281 void CheckUpdateFromSettingsPage();
283 // Show re-enable prompt if the update is initiated from the settings page
284 // and needs additional permissions.
285 void ConfirmReEnable();
287 void set_install_flag(int flag
, bool val
) {
289 install_flags_
|= flag
;
291 install_flags_
&= ~flag
;
294 // The file we're installing.
295 base::FilePath source_file_
;
297 // The URL the file was downloaded from.
300 // The directory extensions are installed to.
301 const base::FilePath install_directory_
;
303 // The location the installation came from (bundled with Chromium, registry,
304 // manual install, etc). This metadata is saved with the installation if
305 // successful. Defaults to INTERNAL.
306 Manifest::Location install_source_
;
308 // Indicates whether the user has already approved the extension to be
309 // installed. If true, |expected_manifest_| and |expected_id_| must match
313 // For updates, external and webstore installs we have an ID we're expecting
314 // the extension to contain.
315 std::string expected_id_
;
317 // An expected hash sum for the .crx file.
318 std::string expected_hash_
;
320 // True if installation failed due to a hash sum mismatch.
321 bool hash_check_failed_
;
323 // A parsed copy of the expected manifest, before any transformations like
324 // localization have taken place. If |approved_| is true, then the
325 // extension's manifest must match this for the install to proceed.
326 scoped_ptr
<Manifest
> expected_manifest_
;
328 // The level of checking when comparing the actual manifest against
329 // the |expected_manifest_|.
330 WebstoreInstaller::ManifestCheckLevel expected_manifest_check_level_
;
332 // If valid, specifies the minimum version we'll install. Installation will
333 // fail if the actual version is smaller.
334 base::Version minimum_version_
;
336 // If valid, contains the expected version of the extension we're installing.
337 // Important for external sources, where claiming the wrong version could
338 // cause unnecessary unpacking of an extension at every restart.
339 // See also |fail_install_if_unexpected_version_|!
340 base::Version expected_version_
;
342 // If true, installation will fail if the actual version doesn't match
343 // |expected_version_|. If false, the extension will still be installed, but
344 // not granted any permissions.
345 bool fail_install_if_unexpected_version_
;
347 // Whether manual extension installation is enabled. We can't just check this
348 // before trying to install because themes are special-cased to always be
350 bool extensions_enabled_
;
352 // Whether we're supposed to delete the source file on destruction. Defaults
356 // Whether to create an app shortcut after successful installation. This is
357 // set based on the user's selection in the UI and can only ever be true for
359 bool create_app_shortcut_
;
361 // The ordinal of the NTP apps page |extension_| will be shown on.
362 syncer::StringOrdinal page_ordinal_
;
364 // A parsed copy of the unmodified original manifest, before any
365 // transformations like localization have taken place.
366 scoped_ptr
<Manifest
> original_manifest_
;
368 // If valid, contains the current version of the extension we're
369 // installing (for upgrades).
370 base::Version current_version_
;
372 // The icon we will display in the installation UI, if any.
373 scoped_ptr
<SkBitmap
> install_icon_
;
375 // The temp directory extension resources were unpacked to. We own this and
376 // must delete it when we are done with it.
377 base::FilePath temp_dir_
;
379 // The frontend we will report results back to.
380 base::WeakPtr
<ExtensionService
> service_weak_
;
382 // The client we will work with to do the installation. This can be NULL, in
383 // which case the install is silent.
384 scoped_ptr
<ExtensionInstallPrompt
> client_
;
386 // The root of the unpacked extension directory. This is a subdirectory of
387 // temp_dir_, so we don't have to delete it explicitly.
388 base::FilePath unpacked_extension_root_
;
390 // True when the CRX being installed was just downloaded.
391 // Used to trigger extra checks before installing.
392 bool apps_require_extension_mime_type_
;
394 // Allows for the possibility of a normal install (one in which a |client|
395 // is provided in the ctor) to proceed without showing the permissions prompt
397 bool allow_silent_install_
;
399 // Allows for the possibility of an installation without granting any
400 // permissions to the extension.
401 bool grant_permissions_
;
403 // The value of the content type header sent with the CRX.
404 // Ignorred unless |require_extension_mime_type_| is true.
405 std::string original_mime_type_
;
407 // What caused this install? Used only for histograms that report
408 // on failure rates, broken down by the cause of the install.
409 extension_misc::CrxInstallCause install_cause_
;
411 // Creation flags to use for the extension. These flags will be used
412 // when calling Extenion::Create() by the crx installer.
415 // Whether to allow off store installation.
416 OffStoreInstallAllowReason off_store_install_allow_reason_
;
418 // Whether the installation was handled successfully. This is used to
419 // indicate to the client whether the file should be removed and any UI
420 // initiating the installation can be removed. This is different than whether
421 // there was an error; if there was an error that rejects installation we
422 // still consider the installation 'handled'.
423 bool did_handle_successfully_
;
425 // Whether we should produce an error if the manifest declares requirements
426 // that are not met. If false and there is an unmet requirement, the install
427 // will continue but the extension will be distabled.
428 bool error_on_unsupported_requirements_
;
430 // Sequenced task runner where file I/O operations will be performed.
431 scoped_refptr
<base::SequencedTaskRunner
> installer_task_runner_
;
433 // Used to show the install dialog.
434 ExtensionInstallPrompt::ShowDialogCallback show_dialog_callback_
;
436 // Whether the update is initiated by the user from the extension settings
438 bool update_from_settings_page_
;
440 // The flags for ExtensionService::OnExtensionInstalled.
443 // Performs requirements, policy and blacklist checks on the extension.
444 ExtensionInstallChecker install_checker_
;
446 DISALLOW_COPY_AND_ASSIGN(CrxInstaller
);
449 } // namespace extensions
451 #endif // CHROME_BROWSER_EXTENSIONS_CRX_INSTALLER_H_