blob: f0a93657b4890db72cad4ecbe5721f52462218f3 [file] [log] [blame]
[email protected]c333e792012-01-06 16:57:391// Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]7577a5c52009-07-30 06:21:582// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chrome/browser/extensions/crx_installer.h"
6
[email protected]5349ac6d2011-04-05 22:20:177#include <map>
[email protected]b1f04cc2010-11-10 22:59:308#include <set>
[email protected]a01e00632010-11-05 16:58:149
[email protected]53612e82011-10-18 18:00:3610#include "base/bind.h"
[email protected]7577a5c52009-07-30 06:21:5811#include "base/file_util.h"
[email protected]ea1a3f62012-11-16 20:34:2312#include "base/files/scoped_temp_dir.h"
[email protected]fee46a82010-12-09 16:42:1513#include "base/lazy_instance.h"
[email protected]394dc472011-04-14 15:57:1914#include "base/metrics/histogram.h"
[email protected]b0b3abd92010-04-30 17:00:0915#include "base/path_service.h"
[email protected]7f8f24f2012-11-15 19:40:1416#include "base/sequenced_task_runner.h"
[email protected]98270432012-09-11 20:51:2417#include "base/string_util.h"
[email protected]18d4b6c2010-09-21 03:21:0418#include "base/stringprintf.h"
[email protected]bc151cf92013-02-12 04:57:2619#include "base/threading/sequenced_worker_pool.h"
[email protected]34b99632011-01-01 01:01:0620#include "base/threading/thread_restrictions.h"
[email protected]f20d7332011-03-08 21:11:5321#include "base/time.h"
[email protected]4bf41352010-03-08 21:21:3622#include "base/utf_string_conversions.h"
[email protected]daf66aa2010-08-06 06:24:2823#include "base/version.h"
[email protected]6657afa62009-11-04 02:15:2024#include "chrome/browser/extensions/convert_user_script.h"
[email protected]bb461532010-11-26 21:50:2325#include "chrome/browser/extensions/convert_web_app.h"
[email protected]993da5e2013-03-23 21:25:1626#include "chrome/browser/extensions/crx_installer_error.h"
[email protected]14a000d2010-04-29 21:44:2427#include "chrome/browser/extensions/extension_error_reporter.h"
[email protected]c82da8c42012-06-08 19:49:1128#include "chrome/browser/extensions/extension_install_ui.h"
[email protected]f20d7332011-03-08 21:11:5329#include "chrome/browser/extensions/extension_service.h"
[email protected]65187152012-06-02 13:14:1430#include "chrome/browser/extensions/extension_system.h"
[email protected]fdd679b2012-11-15 20:49:3931#include "chrome/browser/extensions/management_policy.h"
[email protected]c333e792012-01-06 16:57:3932#include "chrome/browser/extensions/permissions_updater.h"
[email protected]98270432012-09-11 20:51:2433#include "chrome/browser/extensions/requirements_checker.h"
[email protected]21a5ad62012-04-03 04:48:4534#include "chrome/browser/extensions/webstore_installer.h"
35#include "chrome/browser/profiles/profile.h"
[email protected]92bcd162010-01-15 08:47:4836#include "chrome/browser/web_applications/web_app.h"
[email protected]432115822011-07-10 15:52:2737#include "chrome/common/chrome_notification_types.h"
[email protected]b0b3abd92010-04-30 17:00:0938#include "chrome/common/chrome_paths.h"
[email protected]a0cf04a2010-06-23 03:29:5539#include "chrome/common/extensions/extension_constants.h"
[email protected]f20d7332011-03-08 21:11:5340#include "chrome/common/extensions/extension_file_util.h"
[email protected]21a5ad62012-04-03 04:48:4541#include "chrome/common/extensions/extension_icon_set.h"
[email protected]544471a2012-10-13 05:27:0942#include "chrome/common/extensions/feature_switch.h"
[email protected]ac875372013-02-28 04:36:0943#include "chrome/common/extensions/manifest.h"
[email protected]abe720c02013-04-12 04:00:1044#include "chrome/common/extensions/manifest_handlers/icons_handler.h"
[email protected]c38831a12011-10-28 12:44:4945#include "content/public/browser/browser_thread.h"
[email protected]ad50def52011-10-19 23:17:0746#include "content/public/browser/notification_service.h"
[email protected]ea114722012-03-12 01:11:2547#include "content/public/browser/resource_dispatcher_host.h"
[email protected]7f6f44c2011-12-14 13:23:3848#include "content/public/browser/user_metrics.h"
[email protected]7577a5c52009-07-30 06:21:5849#include "grit/chromium_strings.h"
[email protected]ca3dbf52010-05-19 22:27:0650#include "grit/generated_resources.h"
[email protected]969894ab2010-08-29 00:35:0151#include "grit/theme_resources.h"
[email protected]d2817012009-08-04 06:46:2152#include "third_party/skia/include/core/SkBitmap.h"
[email protected]c051a1b2011-01-21 23:30:1753#include "ui/base/l10n/l10n_util.h"
[email protected]42ce29d2011-01-20 23:19:4654#include "ui/base/resource/resource_bundle.h"
[email protected]7577a5c52009-07-30 06:21:5855
[email protected]0d9a1da82013-03-14 21:52:0756#if defined(ENABLE_MANAGED_USERS)
57#include "chrome/browser/managed_mode/managed_user_service.h"
58#include "chrome/browser/managed_mode/managed_user_service_factory.h"
59#endif
60
[email protected]631bb742011-11-02 11:29:3961using content::BrowserThread;
[email protected]7f6f44c2011-12-14 13:23:3862using content::UserMetricsAction;
[email protected]bf3d9df2012-07-24 23:20:2763
64namespace extensions {
[email protected]631bb742011-11-02 11:29:3965
[email protected]aa9fc862012-05-30 21:47:4766namespace {
67
68// Used in histograms; do not change order.
[email protected]7224dbd2012-06-05 15:21:5069enum OffStoreInstallDecision {
70 OnStoreInstall,
71 OffStoreInstallAllowed,
72 OffStoreInstallDisallowed,
73 NumOffStoreInstallDecision
[email protected]aa9fc862012-05-30 21:47:4774};
75
76} // namespace
77
[email protected]dd9d6272010-09-09 17:33:1878// static
[email protected]d8c8f25f2011-11-02 18:18:0179scoped_refptr<CrxInstaller> CrxInstaller::Create(
80 ExtensionService* frontend,
[email protected]c82da8c42012-06-08 19:49:1181 ExtensionInstallPrompt* client) {
[email protected]21a5ad62012-04-03 04:48:4582 return new CrxInstaller(frontend->AsWeakPtr(), client, NULL);
[email protected]d8c8f25f2011-11-02 18:18:0183}
84
85// static
[email protected]21a5ad62012-04-03 04:48:4586scoped_refptr<CrxInstaller> CrxInstaller::Create(
87 ExtensionService* frontend,
[email protected]c82da8c42012-06-08 19:49:1188 ExtensionInstallPrompt* client,
[email protected]bf3d9df2012-07-24 23:20:2789 const WebstoreInstaller::Approval* approval) {
[email protected]21a5ad62012-04-03 04:48:4590 return new CrxInstaller(frontend->AsWeakPtr(), client, approval);
[email protected]5349ac6d2011-04-05 22:20:1791}
92
[email protected]3d61a7f2012-07-12 19:11:2593CrxInstaller::CrxInstaller(
94 base::WeakPtr<ExtensionService> frontend_weak,
95 ExtensionInstallPrompt* client,
[email protected]bf3d9df2012-07-24 23:20:2796 const WebstoreInstaller::Approval* approval)
[email protected]14908b72011-04-20 06:54:3697 : install_directory_(frontend_weak->install_directory()),
[email protected]1d5e58b2013-01-31 08:41:4098 install_source_(Manifest::INTERNAL),
[email protected]21a5ad62012-04-03 04:48:4599 approved_(false),
[email protected]14908b72011-04-20 06:54:36100 extensions_enabled_(frontend_weak->extensions_enabled()),
[email protected]6dfbbf82010-03-12 23:09:16101 delete_source_(false),
[email protected]6451e332010-10-05 00:14:53102 create_app_shortcut_(false),
[email protected]14908b72011-04-20 06:54:36103 frontend_weak_(frontend_weak),
[email protected]655b2b1a2011-10-13 17:13:06104 profile_(frontend_weak->profile()),
[email protected]d4a71882010-06-25 16:36:41105 client_(client),
[email protected]dd9d6272010-09-09 17:33:18106 apps_require_extension_mime_type_(false),
[email protected]cb0e50312011-05-09 15:03:07107 allow_silent_install_(false),
[email protected]bc151cf92013-02-12 04:57:26108 bypass_blacklist_for_test_(false),
[email protected]1bf73cc2011-10-26 22:38:31109 install_cause_(extension_misc::INSTALL_CAUSE_UNSET),
[email protected]a9736892012-05-30 15:58:05110 creation_flags_(Extension::NO_FLAGS),
[email protected]86a99112012-06-19 01:18:07111 off_store_install_allow_reason_(OffStoreInstallDisallowed),
[email protected]b70a2d92012-06-28 19:51:21112 did_handle_successfully_(true),
[email protected]98270432012-09-11 20:51:24113 error_on_unsupported_requirements_(false),
[email protected]702d8b42013-02-27 20:55:50114 requirements_checker_(new RequirementsChecker()),
[email protected]0db124b02012-11-07 04:55:05115 has_requirement_errors_(false),
[email protected]b86b9ee2013-03-01 01:58:29116 install_wait_for_idle_(true),
117 update_from_settings_page_(false) {
[email protected]7f8f24f2012-11-15 19:40:14118 installer_task_runner_ = frontend_weak->GetFileTaskRunner();
[email protected]21a5ad62012-04-03 04:48:45119 if (!approval)
120 return;
121
122 CHECK(profile_->IsSameProfile(approval->profile));
[email protected]d2a639e2012-09-17 07:41:21123 if (client_) {
124 client_->install_ui()->SetUseAppInstalledBubble(
125 approval->use_app_installed_bubble);
126 client_->install_ui()->SetSkipPostInstallUI(approval->skip_post_install_ui);
127 }
[email protected]21a5ad62012-04-03 04:48:45128
[email protected]89019d62012-05-17 18:47:09129 if (approval->skip_install_dialog) {
130 // Mark the extension as approved, but save the expected manifest and ID
131 // so we can check that they match the CRX's.
132 approved_ = true;
[email protected]21c01042013-03-10 23:41:14133 expected_manifest_.reset(approval->manifest->DeepCopy());
[email protected]89019d62012-05-17 18:47:09134 expected_id_ = approval->extension_id;
135 }
[email protected]af6efb22012-10-12 02:23:05136
137 show_dialog_callback_ = approval->show_dialog_callback;
[email protected]7577a5c52009-07-30 06:21:58138}
139
[email protected]2a464a92009-08-01 17:58:35140CrxInstaller::~CrxInstaller() {
[email protected]765b7ea52010-03-30 03:40:34141 // Make sure the UI is deleted on the ui thread.
[email protected]d2a639e2012-09-17 07:41:21142 if (client_) {
143 BrowserThread::DeleteSoon(BrowserThread::UI, FROM_HERE, client_);
144 client_ = NULL;
145 }
[email protected]2a464a92009-08-01 17:58:35146}
147
[email protected]650b2d52013-02-10 03:41:45148void CrxInstaller::InstallCrx(const base::FilePath& source_file) {
[email protected]6dfbbf82010-03-12 23:09:16149 source_file_ = source_file;
150
[email protected]bf3d9df2012-07-24 23:20:27151 scoped_refptr<SandboxedUnpacker> unpacker(
152 new SandboxedUnpacker(
[email protected]6dfbbf82010-03-12 23:09:16153 source_file,
[email protected]ea114722012-03-12 01:11:25154 content::ResourceDispatcherHost::Get() != NULL,
[email protected]fc38935a2011-10-31 23:53:28155 install_source_,
[email protected]1bf73cc2011-10-26 22:38:31156 creation_flags_,
[email protected]171ab92d2012-10-19 01:16:34157 install_directory_,
[email protected]7f8f24f2012-11-15 19:40:14158 installer_task_runner_,
[email protected]6dfbbf82010-03-12 23:09:16159 this));
160
[email protected]7f8f24f2012-11-15 19:40:14161 if (!installer_task_runner_->PostTask(
162 FROM_HERE,
[email protected]bf3d9df2012-07-24 23:20:27163 base::Bind(&SandboxedUnpacker::Start, unpacker.get())))
[email protected]14908b72011-04-20 06:54:36164 NOTREACHED();
[email protected]6dfbbf82010-03-12 23:09:16165}
166
[email protected]650b2d52013-02-10 03:41:45167void CrxInstaller::InstallUserScript(const base::FilePath& source_file,
[email protected]655b2b1a2011-10-13 17:13:06168 const GURL& download_url) {
169 DCHECK(!download_url.is_empty());
[email protected]6dfbbf82010-03-12 23:09:16170
171 source_file_ = source_file;
[email protected]655b2b1a2011-10-13 17:13:06172 download_url_ = download_url;
[email protected]6dfbbf82010-03-12 23:09:16173
[email protected]7f8f24f2012-11-15 19:40:14174 if (!installer_task_runner_->PostTask(
175 FROM_HERE,
[email protected]53612e82011-10-18 18:00:36176 base::Bind(&CrxInstaller::ConvertUserScriptOnFileThread, this)))
[email protected]14908b72011-04-20 06:54:36177 NOTREACHED();
[email protected]6dfbbf82010-03-12 23:09:16178}
179
[email protected]6657afa62009-11-04 02:15:20180void CrxInstaller::ConvertUserScriptOnFileThread() {
[email protected]fc670822011-12-17 09:33:49181 string16 error;
[email protected]bf3d9df2012-07-24 23:20:27182 scoped_refptr<Extension> extension = ConvertUserScriptToExtension(
[email protected]171ab92d2012-10-19 01:16:34183 source_file_, download_url_, install_directory_, &error);
[email protected]6657afa62009-11-04 02:15:20184 if (!extension) {
[email protected]4eaf0b32012-06-19 06:33:28185 ReportFailureFromFileThread(CrxInstallerError(error));
[email protected]6657afa62009-11-04 02:15:20186 return;
187 }
188
[email protected]ad93c6ba2011-05-26 04:48:33189 OnUnpackSuccess(extension->path(), extension->path(), NULL, extension);
[email protected]6657afa62009-11-04 02:15:20190}
191
[email protected]bb461532010-11-26 21:50:23192void CrxInstaller::InstallWebApp(const WebApplicationInfo& web_app) {
[email protected]7f8f24f2012-11-15 19:40:14193 if (!installer_task_runner_->PostTask(
194 FROM_HERE,
[email protected]171ab92d2012-10-19 01:16:34195 base::Bind(&CrxInstaller::ConvertWebAppOnFileThread,
196 this,
197 web_app,
198 install_directory_)))
[email protected]14908b72011-04-20 06:54:36199 NOTREACHED();
[email protected]bb461532010-11-26 21:50:23200}
201
202void CrxInstaller::ConvertWebAppOnFileThread(
[email protected]650b2d52013-02-10 03:41:45203 const WebApplicationInfo& web_app,
204 const base::FilePath& install_directory) {
[email protected]fc670822011-12-17 09:33:49205 string16 error;
[email protected]bb461532010-11-26 21:50:23206 scoped_refptr<Extension> extension(
[email protected]171ab92d2012-10-19 01:16:34207 ConvertWebAppToExtension(web_app, base::Time::Now(), install_directory));
[email protected]bb461532010-11-26 21:50:23208 if (!extension) {
209 // Validation should have stopped any potential errors before getting here.
210 NOTREACHED() << "Could not convert web app to extension.";
211 return;
212 }
213
214 // TODO(aa): conversion data gets lost here :(
215
[email protected]ad93c6ba2011-05-26 04:48:33216 OnUnpackSuccess(extension->path(), extension->path(), NULL, extension);
[email protected]bb461532010-11-26 21:50:23217}
218
[email protected]4eaf0b32012-06-19 06:33:28219CrxInstallerError CrxInstaller::AllowInstall(const Extension* extension) {
[email protected]7f8f24f2012-11-15 19:40:14220 DCHECK(installer_task_runner_->RunsTasksOnCurrentThread());
[email protected]da8479bf2010-10-08 15:19:45221
[email protected]21a5ad62012-04-03 04:48:45222 // Make sure the expected ID matches if one was supplied or if we want to
223 // bypass the prompt.
224 if ((approved_ || !expected_id_.empty()) &&
225 expected_id_ != extension->id()) {
[email protected]4eaf0b32012-06-19 06:33:28226 return CrxInstallerError(
227 l10n_util::GetStringFUTF16(IDS_EXTENSION_INSTALL_UNEXPECTED_ID,
228 ASCIIToUTF16(expected_id_),
229 ASCIIToUTF16(extension->id())));
[email protected]604322d2011-03-22 16:51:56230 }
231
232 if (expected_version_.get() &&
233 !expected_version_->Equals(*extension->version())) {
[email protected]4eaf0b32012-06-19 06:33:28234 return CrxInstallerError(
235 l10n_util::GetStringFUTF16(
236 IDS_EXTENSION_INSTALL_UNEXPECTED_VERSION,
237 ASCIIToUTF16(expected_version_->GetString()),
238 ASCIIToUTF16(extension->version()->GetString())));
[email protected]604322d2011-03-22 16:51:56239 }
240
[email protected]21a5ad62012-04-03 04:48:45241 // Make sure the manifests match if we want to bypass the prompt.
242 if (approved_ &&
243 (!expected_manifest_.get() ||
244 !expected_manifest_->Equals(original_manifest_.get()))) {
[email protected]4eaf0b32012-06-19 06:33:28245 return CrxInstallerError(
246 l10n_util::GetStringUTF16(IDS_EXTENSION_MANIFEST_INVALID));
[email protected]21a5ad62012-04-03 04:48:45247 }
248
[email protected]604322d2011-03-22 16:51:56249 // The checks below are skipped for themes and external installs.
[email protected]65187152012-06-02 13:14:14250 // TODO(pamg): After ManagementPolicy refactoring is complete, remove this
251 // and other uses of install_source_ that are no longer needed now that the
[email protected]f5ac2742012-07-02 17:50:58252 // SandboxedUnpacker sets extension->location.
[email protected]1d5e58b2013-01-31 08:41:40253 if (extension->is_theme() || Manifest::IsExternalLocation(install_source_))
[email protected]4eaf0b32012-06-19 06:33:28254 return CrxInstallerError();
[email protected]da8479bf2010-10-08 15:19:45255
256 if (!extensions_enabled_) {
[email protected]4eaf0b32012-06-19 06:33:28257 return CrxInstallerError(
258 l10n_util::GetStringUTF16(IDS_EXTENSION_INSTALL_NOT_ENABLED));
[email protected]da8479bf2010-10-08 15:19:45259 }
260
[email protected]7224dbd2012-06-05 15:21:50261 if (install_cause_ == extension_misc::INSTALL_CAUSE_USER_DOWNLOAD) {
[email protected]544471a2012-10-13 05:27:09262 if (FeatureSwitch::easy_off_store_install()->IsEnabled()) {
[email protected]7224dbd2012-06-05 15:21:50263 const char* kHistogramName = "Extensions.OffStoreInstallDecisionEasy";
264 if (is_gallery_install()) {
265 UMA_HISTOGRAM_ENUMERATION(kHistogramName, OnStoreInstall,
266 NumOffStoreInstallDecision);
267 } else {
268 UMA_HISTOGRAM_ENUMERATION(kHistogramName, OffStoreInstallAllowed,
269 NumOffStoreInstallDecision);
270 }
271 } else {
272 const char* kHistogramName = "Extensions.OffStoreInstallDecisionHard";
273 if (is_gallery_install()) {
274 UMA_HISTOGRAM_ENUMERATION(kHistogramName, OnStoreInstall,
275 NumOffStoreInstallDecision);
[email protected]d9039812012-06-09 06:05:48276 } else if (off_store_install_allow_reason_ != OffStoreInstallDisallowed) {
[email protected]7224dbd2012-06-05 15:21:50277 UMA_HISTOGRAM_ENUMERATION(kHistogramName, OffStoreInstallAllowed,
278 NumOffStoreInstallDecision);
[email protected]d9039812012-06-09 06:05:48279 UMA_HISTOGRAM_ENUMERATION("Extensions.OffStoreInstallAllowReason",
280 off_store_install_allow_reason_,
281 NumOffStoreInstallAllowReasons);
[email protected]7224dbd2012-06-05 15:21:50282 } else {
283 UMA_HISTOGRAM_ENUMERATION(kHistogramName, OffStoreInstallDisallowed,
284 NumOffStoreInstallDecision);
[email protected]86a99112012-06-19 01:18:07285 // Don't delete source in this case so that the user can install
286 // manually if they want.
287 delete_source_ = false;
288 did_handle_successfully_ = false;
[email protected]4eaf0b32012-06-19 06:33:28289
290 return CrxInstallerError(
291 CrxInstallerError::ERROR_OFF_STORE,
292 l10n_util::GetStringUTF16(
293 IDS_EXTENSION_INSTALL_DISALLOWED_ON_SITE));
[email protected]7224dbd2012-06-05 15:21:50294 }
295 }
296 }
297
[email protected]da8479bf2010-10-08 15:19:45298 if (extension_->is_app()) {
299 // If the app was downloaded, apps_require_extension_mime_type_
300 // will be set. In this case, check that it was served with the
301 // right mime type. Make an exception for file URLs, which come
302 // from the users computer and have no headers.
[email protected]655b2b1a2011-10-13 17:13:06303 if (!download_url_.SchemeIsFile() &&
[email protected]da8479bf2010-10-08 15:19:45304 apps_require_extension_mime_type_ &&
305 original_mime_type_ != Extension::kMimeType) {
[email protected]4eaf0b32012-06-19 06:33:28306 return CrxInstallerError(
307 l10n_util::GetStringFUTF16(
308 IDS_EXTENSION_INSTALL_INCORRECT_APP_CONTENT_TYPE,
309 ASCIIToUTF16(Extension::kMimeType)));
[email protected]da8479bf2010-10-08 15:19:45310 }
311
[email protected]c08931b2010-10-08 22:30:47312 // If the client_ is NULL, then the app is either being installed via
313 // an internal mechanism like sync, external_extensions, or default apps.
314 // In that case, we don't want to enforce things like the install origin.
[email protected]fc38935a2011-10-31 23:53:28315 if (!is_gallery_install() && client_) {
[email protected]c08931b2010-10-08 22:30:47316 // For apps with a gallery update URL, require that they be installed
317 // from the gallery.
318 // TODO(erikkay) Apply this rule for paid extensions and themes as well.
[email protected]a65882c2010-11-12 15:15:09319 if (extension->UpdatesFromGallery()) {
[email protected]4eaf0b32012-06-19 06:33:28320 return CrxInstallerError(
321 l10n_util::GetStringFUTF16(
322 IDS_EXTENSION_DISALLOW_NON_DOWNLOADED_GALLERY_INSTALLS,
323 l10n_util::GetStringUTF16(IDS_EXTENSION_WEB_STORE_TITLE)));
[email protected]c08931b2010-10-08 22:30:47324 }
325
326 // For self-hosted apps, verify that the entire extent is on the same
327 // host (or a subdomain of the host) the download happened from. There's
328 // no way for us to verify that the app controls any other hosts.
[email protected]ac2e2acd2013-03-21 12:57:29329 URLPattern pattern(UserScript::ValidUserScriptSchemes());
[email protected]655b2b1a2011-10-13 17:13:06330 pattern.SetHost(download_url_.host());
[email protected]06e8b8ff2011-07-13 15:03:47331 pattern.SetMatchSubdomains(true);
[email protected]da8479bf2010-10-08 15:19:45332
[email protected]06e8b8ff2011-07-13 15:03:47333 URLPatternSet patterns = extension_->web_extent();
334 for (URLPatternSet::const_iterator i = patterns.begin();
335 i != patterns.end(); ++i) {
336 if (!pattern.MatchesHost(i->host())) {
[email protected]4eaf0b32012-06-19 06:33:28337 return CrxInstallerError(
338 l10n_util::GetStringUTF16(
339 IDS_EXTENSION_INSTALL_INCORRECT_INSTALL_HOST));
[email protected]da8479bf2010-10-08 15:19:45340 }
341 }
[email protected]da8479bf2010-10-08 15:19:45342 }
343 }
344
[email protected]4eaf0b32012-06-19 06:33:28345 return CrxInstallerError();
[email protected]da8479bf2010-10-08 15:19:45346}
347
[email protected]fc670822011-12-17 09:33:49348void CrxInstaller::OnUnpackFailure(const string16& error_message) {
[email protected]7f8f24f2012-11-15 19:40:14349 DCHECK(installer_task_runner_->RunsTasksOnCurrentThread());
[email protected]cb0e50312011-05-09 15:03:07350
351 UMA_HISTOGRAM_ENUMERATION("Extensions.UnpackFailureInstallSource",
[email protected]1d5e58b2013-01-31 08:41:40352 install_source(), Manifest::NUM_LOCATIONS);
[email protected]cb0e50312011-05-09 15:03:07353
[email protected]cb0e50312011-05-09 15:03:07354 UMA_HISTOGRAM_ENUMERATION("Extensions.UnpackFailureInstallCause",
355 install_cause(),
356 extension_misc::NUM_INSTALL_CAUSES);
357
[email protected]4eaf0b32012-06-19 06:33:28358 ReportFailureFromFileThread(CrxInstallerError(error_message));
[email protected]7577a5c52009-07-30 06:21:58359}
360
[email protected]650b2d52013-02-10 03:41:45361void CrxInstaller::OnUnpackSuccess(const base::FilePath& temp_dir,
362 const base::FilePath& extension_dir,
[email protected]ad93c6ba2011-05-26 04:48:33363 const DictionaryValue* original_manifest,
[email protected]9adb9692010-10-29 23:14:02364 const Extension* extension) {
[email protected]7f8f24f2012-11-15 19:40:14365 DCHECK(installer_task_runner_->RunsTasksOnCurrentThread());
[email protected]2a464a92009-08-01 17:58:35366
[email protected]cb0e50312011-05-09 15:03:07367 UMA_HISTOGRAM_ENUMERATION("Extensions.UnpackSuccessInstallSource",
[email protected]1d5e58b2013-01-31 08:41:40368 install_source(), Manifest::NUM_LOCATIONS);
[email protected]cb0e50312011-05-09 15:03:07369
370
371 UMA_HISTOGRAM_ENUMERATION("Extensions.UnpackSuccessInstallCause",
372 install_cause(),
373 extension_misc::NUM_INSTALL_CAUSES);
374
[email protected]7577a5c52009-07-30 06:21:58375 // Note: We take ownership of |extension| and |temp_dir|.
[email protected]66e4eb32010-10-27 20:37:41376 extension_ = extension;
[email protected]7577a5c52009-07-30 06:21:58377 temp_dir_ = temp_dir;
378
[email protected]ad93c6ba2011-05-26 04:48:33379 if (original_manifest)
[email protected]21c01042013-03-10 23:41:14380 original_manifest_.reset(new Manifest(
381 Manifest::INVALID_LOCATION,
382 scoped_ptr<DictionaryValue>(original_manifest->DeepCopy())));
[email protected]ad93c6ba2011-05-26 04:48:33383
[email protected]8ef78fd2010-08-19 17:14:32384 // We don't have to delete the unpack dir explicity since it is a child of
[email protected]7577a5c52009-07-30 06:21:58385 // the temp dir.
386 unpacked_extension_root_ = extension_dir;
[email protected]7577a5c52009-07-30 06:21:58387
[email protected]4eaf0b32012-06-19 06:33:28388 CrxInstallerError error = AllowInstall(extension);
389 if (error.type() != CrxInstallerError::ERROR_NONE) {
[email protected]da8479bf2010-10-08 15:19:45390 ReportFailureFromFileThread(error);
[email protected]7577a5c52009-07-30 06:21:58391 return;
392 }
393
[email protected]7a5452f2010-12-13 23:03:19394 if (client_) {
[email protected]702d8b42013-02-27 20:55:50395 IconsInfo::DecodeIcon(extension_.get(),
[email protected]faf87192012-08-17 00:07:59396 extension_misc::EXTENSION_ICON_LARGE,
[email protected]e3c0bc22012-02-24 01:34:15397 ExtensionIconSet::MATCH_BIGGER,
[email protected]c690a9812009-12-17 05:55:32398 &install_icon_);
[email protected]866930682009-08-18 22:53:47399 }
[email protected]92bcd162010-01-15 08:47:48400
[email protected]14908b72011-04-20 06:54:36401 if (!BrowserThread::PostTask(
[email protected]98270432012-09-11 20:51:24402 BrowserThread::UI, FROM_HERE,
403 base::Bind(&CrxInstaller::CheckRequirements, this)))
[email protected]14908b72011-04-20 06:54:36404 NOTREACHED();
[email protected]7577a5c52009-07-30 06:21:58405}
406
[email protected]98270432012-09-11 20:51:24407void CrxInstaller::CheckRequirements() {
408 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]b80ec462012-10-30 18:53:00409 if (!frontend_weak_.get() || frontend_weak_->browser_terminating())
[email protected]3c4abc82012-10-22 22:25:54410 return;
[email protected]98270432012-09-11 20:51:24411 AddRef(); // Balanced in OnRequirementsChecked().
412 requirements_checker_->Check(extension_,
413 base::Bind(&CrxInstaller::OnRequirementsChecked,
414 this));
415}
416
417void CrxInstaller::OnRequirementsChecked(
418 std::vector<std::string> requirement_errors) {
419 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
420 Release(); // Balanced in CheckRequirements().
421 if (!requirement_errors.empty()) {
422 if (error_on_unsupported_requirements_) {
423 ReportFailureFromUIThread(CrxInstallerError(
424 UTF8ToUTF16(JoinString(requirement_errors, ' '))));
425 return;
426 }
427 has_requirement_errors_ = true;
428 }
429
[email protected]9cbd5912013-04-18 11:27:54430#if defined(ENABLE_MANAGED_USERS) && !defined(OS_CHROMEOS)
[email protected]0d9a1da82013-03-14 21:52:07431 // Check whether the profile is managed.
432 ManagedUserService* service =
433 ManagedUserServiceFactory::GetForProfile(profile_);
434 if (service->ProfileIsManaged()) {
[email protected]a9bc63e2013-03-21 14:54:43435 // Extensions which should be installed by policy are installed without
436 // using the ExtensionInstallPrompt. In that case, |client_| is NULL.
437 if (client_ == NULL) {
438 // Automatically set authorization
439 OnAuthorizationResult(true);
440 return;
441 }
[email protected]509ad1a92013-03-19 21:41:06442 // parent_web_contents could be NULL when the client is instantiated from
443 // ExtensionEnableFlow, but that code path does not lead to here.
[email protected]a9bc63e2013-03-21 14:54:43444 CHECK(client_->parent_web_contents());
[email protected]509ad1a92013-03-19 21:41:06445 service->RequestAuthorization(
446 client_->parent_web_contents(),
[email protected]0d9a1da82013-03-14 21:52:07447 base::Bind(&CrxInstaller::OnAuthorizationResult,
448 this));
449 return;
450 }
451#endif
[email protected]98270432012-09-11 20:51:24452 ConfirmInstall();
453}
454
[email protected]0d9a1da82013-03-14 21:52:07455#if defined(ENABLE_MANAGED_USERS)
456void CrxInstaller::OnAuthorizationResult(bool success) {
457 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
458 if (success) {
459 ManagedUserService* service =
460 ManagedUserServiceFactory::GetForProfile(profile_);
461 DCHECK(service);
462 service->AddElevationForExtension(extension_->id());
463 }
464 // In case the authorization was not successful, ConfirmInstall will give an
465 // appropriate error to the user.
466 ConfirmInstall();
467}
468#endif
469
[email protected]d2817012009-08-04 06:46:21470void CrxInstaller::ConfirmInstall() {
[email protected]ca4b5fa32010-10-09 12:42:18471 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]b80ec462012-10-30 18:53:00472 if (!frontend_weak_.get() || frontend_weak_->browser_terminating())
[email protected]14908b72011-04-20 06:54:36473 return;
474
[email protected]b86b9ee2013-03-01 01:58:29475 // Check whether this install is initiated from the settings page to
476 // update an existing extension or app.
477 CheckUpdateFromSettingsPage();
478
[email protected]0d9a1da82013-03-14 21:52:07479 // For managed users the call UserMayLoad returns false if the profile is not
480 // elevated.
[email protected]65187152012-06-02 13:14:14481 string16 error;
[email protected]bf3d9df2012-07-24 23:20:27482 if (!ExtensionSystem::Get(profile_)->management_policy()->
[email protected]bd306722012-07-11 20:43:59483 UserMayLoad(extension_, &error)) {
[email protected]4eaf0b32012-06-19 06:33:28484 ReportFailureFromUIThread(CrxInstallerError(error));
[email protected]306a2bd2010-08-11 14:56:36485 return;
486 }
487
[email protected]0d9a1da82013-03-14 21:52:07488#if defined(ENABLE_MANAGED_USERS)
489 // Reset the elevation of managed users.
490 ManagedUserService* service =
491 ManagedUserServiceFactory::GetForProfile(profile_);
492 if (service->ProfileIsManaged())
493 service->RemoveElevationForExtension(extension_->id());
494#endif
495
[email protected]6d2e60bd2010-06-03 22:37:39496 GURL overlapping_url;
[email protected]9adb9692010-10-29 23:14:02497 const Extension* overlapping_extension =
[email protected]615d88f2011-12-13 01:47:44498 frontend_weak_->extensions()->
499 GetHostedAppByOverlappingWebExtent(extension_->web_extent());
[email protected]15300d92011-01-19 18:44:30500 if (overlapping_extension &&
501 overlapping_extension->id() != extension_->id()) {
[email protected]4eaf0b32012-06-19 06:33:28502 ReportFailureFromUIThread(
503 CrxInstallerError(
504 l10n_util::GetStringFUTF16(
505 IDS_EXTENSION_OVERLAPPING_WEB_EXTENT,
506 UTF8ToUTF16(overlapping_extension->name()))));
[email protected]6d2e60bd2010-06-03 22:37:39507 return;
508 }
509
[email protected]b6ab96d2009-08-20 18:58:19510 current_version_ =
[email protected]14908b72011-04-20 06:54:36511 frontend_weak_->extension_prefs()->GetVersionString(extension_->id());
[email protected]b6ab96d2009-08-20 18:58:19512
[email protected]b86b9ee2013-03-01 01:58:29513 if (client_ &&
514 (!allow_silent_install_ || !approved_) &&
515 !update_from_settings_page_) {
516 AddRef(); // Balanced in InstallUIProceed() and InstallUIAbort().
[email protected]af6efb22012-10-12 02:23:05517 client_->ConfirmInstall(this, extension_.get(), show_dialog_callback_);
[email protected]6b75ec32009-08-14 06:37:18518 } else {
[email protected]7f8f24f2012-11-15 19:40:14519 if (!installer_task_runner_->PostTask(
520 FROM_HERE,
[email protected]53612e82011-10-18 18:00:36521 base::Bind(&CrxInstaller::CompleteInstall, this)))
[email protected]14908b72011-04-20 06:54:36522 NOTREACHED();
[email protected]6b75ec32009-08-14 06:37:18523 }
524 return;
[email protected]d2817012009-08-04 06:46:21525}
526
[email protected]ba9c96c62010-09-14 02:38:02527void CrxInstaller::InstallUIProceed() {
[email protected]b86b9ee2013-03-01 01:58:29528 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]d2817012009-08-04 06:46:21529
[email protected]b86b9ee2013-03-01 01:58:29530 if (!frontend_weak_.get() || frontend_weak_->browser_terminating())
531 return;
532
533 // If update_from_settings_page_ boolean is true, this functions is
534 // getting called in response to ExtensionInstallPrompt::ConfirmReEnable()
535 // and if it is false, this function is called in response to
536 // ExtensionInstallPrompt::ConfirmInstall().
537 if (update_from_settings_page_) {
[email protected]009633c2013-03-07 22:08:28538 frontend_weak_->GrantPermissionsAndEnableExtension(extension_.get());
[email protected]b86b9ee2013-03-01 01:58:29539 } else {
540 if (!installer_task_runner_->PostTask(
541 FROM_HERE,
542 base::Bind(&CrxInstaller::CompleteInstall, this)))
543 NOTREACHED();
544 }
545
546 Release(); // balanced in ConfirmInstall() or ConfirmReEnable().
[email protected]d2817012009-08-04 06:46:21547}
548
[email protected]d828fac2011-06-28 05:43:04549void CrxInstaller::InstallUIAbort(bool user_initiated) {
[email protected]b86b9ee2013-03-01 01:58:29550 // If update_from_settings_page_ boolean is true, this functions is
551 // getting called in response to ExtensionInstallPrompt::ConfirmReEnable()
552 // and if it is false, this function is called in response to
553 // ExtensionInstallPrompt::ConfirmInstall().
554 if (!update_from_settings_page_) {
555 std::string histogram_name = user_initiated ?
556 "Extensions.Permissions_InstallCancel" :
557 "Extensions.Permissions_InstallAbort";
558 ExtensionService::RecordPermissionMessagesHistogram(
559 extension_, histogram_name.c_str());
[email protected]fe2dd7742011-04-19 22:52:49560
[email protected]b86b9ee2013-03-01 01:58:29561 // Kill the theme loading bubble.
562 content::NotificationService* service =
563 content::NotificationService::current();
564 service->Notify(chrome::NOTIFICATION_NO_THEME_DETECTED,
565 content::Source<CrxInstaller>(this),
566 content::NotificationService::NoDetails());
[email protected]d2817012009-08-04 06:46:21567
[email protected]b86b9ee2013-03-01 01:58:29568 NotifyCrxInstallComplete(false);
569 }
[email protected]052ec1a3e2011-06-06 14:12:48570
[email protected]b86b9ee2013-03-01 01:58:29571 Release(); // balanced in ConfirmInstall() or ConfirmReEnable().
[email protected]c544be52012-07-17 01:08:37572
[email protected]d2817012009-08-04 06:46:21573 // We're done. Since we don't post any more tasks to ourself, our ref count
574 // should go to zero and we die. The destructor will clean up the temp dir.
[email protected]7577a5c52009-07-30 06:21:58575}
576
577void CrxInstaller::CompleteInstall() {
[email protected]7f8f24f2012-11-15 19:40:14578 DCHECK(installer_task_runner_->RunsTasksOnCurrentThread());
[email protected]2a464a92009-08-01 17:58:35579
[email protected]ca3dbf52010-05-19 22:27:06580 if (!current_version_.empty()) {
[email protected]12126d372012-07-11 18:40:53581 Version current_version(current_version_);
582 if (current_version.CompareTo(*(extension_->version())) > 0) {
[email protected]30e10d882011-04-22 19:36:29583 ReportFailureFromFileThread(
[email protected]4eaf0b32012-06-19 06:33:28584 CrxInstallerError(
[email protected]bf71eb72012-09-13 20:29:28585 l10n_util::GetStringUTF16(extension_->is_app() ?
586 IDS_APP_CANT_DOWNGRADE_VERSION :
587 IDS_EXTENSION_CANT_DOWNGRADE_VERSION)));
[email protected]ca3dbf52010-05-19 22:27:06588 return;
589 }
[email protected]7577a5c52009-07-30 06:21:58590 }
591
[email protected]394dc472011-04-14 15:57:19592 // See how long extension install paths are. This is important on
593 // windows, because file operations may fail if the path to a file
594 // exceeds a small constant. See crbug.com/69693 .
595 UMA_HISTOGRAM_CUSTOM_COUNTS(
596 "Extensions.CrxInstallDirPathLength",
597 install_directory_.value().length(), 0, 500, 100);
598
[email protected]650b2d52013-02-10 03:41:45599 base::FilePath version_dir = extension_file_util::InstallExtension(
[email protected]ca3dbf52010-05-19 22:27:06600 unpacked_extension_root_,
601 extension_->id(),
602 extension_->VersionString(),
603 install_directory_);
604 if (version_dir.empty()) {
605 ReportFailureFromFileThread(
[email protected]4eaf0b32012-06-19 06:33:28606 CrxInstallerError(
607 l10n_util::GetStringUTF16(
608 IDS_EXTENSION_MOVE_DIRECTORY_TO_PROFILE_FAILED)));
[email protected]b6ab96d2009-08-20 18:58:19609 return;
610 }
611
[email protected]d2817012009-08-04 06:46:21612 // This is lame, but we must reload the extension because absolute paths
613 // inside the content scripts are established inside InitFromValue() and we
614 // just moved the extension.
615 // TODO(aa): All paths to resources inside extensions should be created
616 // lazily and based on the Extension's root path at that moment.
[email protected]fc670822011-12-17 09:33:49617 // TODO(rdevlin.cronin): Continue removing std::string errors and replacing
618 // with string16
[email protected]7c6de19b2012-08-28 04:07:13619 std::string extension_id = extension_->id();
[email protected]d2817012009-08-04 06:46:21620 std::string error;
[email protected]66e4eb32010-10-27 20:37:41621 extension_ = extension_file_util::LoadExtension(
[email protected]542258c2011-03-04 21:25:31622 version_dir,
623 install_source_,
[email protected]fc38935a2011-10-31 23:53:28624 extension_->creation_flags() | Extension::REQUIRE_KEY,
[email protected]542258c2011-03-04 21:25:31625 &error);
[email protected]7c6de19b2012-08-28 04:07:13626
[email protected]6d8c3882012-09-05 02:19:44627 if (extension_) {
628 ReportSuccessFromFileThread();
629 } else {
[email protected]bc151cf92013-02-12 04:57:26630 LOG(ERROR) << error << " " << extension_id << " " << download_url_;
[email protected]6d8c3882012-09-05 02:19:44631 ReportFailureFromFileThread(CrxInstallerError(UTF8ToUTF16(error)));
632 }
[email protected]d2817012009-08-04 06:46:21633
[email protected]7577a5c52009-07-30 06:21:58634}
635
[email protected]4eaf0b32012-06-19 06:33:28636void CrxInstaller::ReportFailureFromFileThread(const CrxInstallerError& error) {
[email protected]7f8f24f2012-11-15 19:40:14637 DCHECK(installer_task_runner_->RunsTasksOnCurrentThread());
[email protected]14908b72011-04-20 06:54:36638 if (!BrowserThread::PostTask(
639 BrowserThread::UI, FROM_HERE,
[email protected]4eaf0b32012-06-19 06:33:28640 base::Bind(&CrxInstaller::ReportFailureFromUIThread, this, error))) {
[email protected]14908b72011-04-20 06:54:36641 NOTREACHED();
[email protected]4eaf0b32012-06-19 06:33:28642 }
[email protected]7577a5c52009-07-30 06:21:58643}
644
[email protected]4eaf0b32012-06-19 06:33:28645void CrxInstaller::ReportFailureFromUIThread(const CrxInstallerError& error) {
[email protected]ca4b5fa32010-10-09 12:42:18646 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]2a464a92009-08-01 17:58:35647
[email protected]ad50def52011-10-19 23:17:07648 content::NotificationService* service =
649 content::NotificationService::current();
[email protected]432115822011-07-10 15:52:27650 service->Notify(chrome::NOTIFICATION_EXTENSION_INSTALL_ERROR,
[email protected]6c2381d2011-10-19 02:52:53651 content::Source<CrxInstaller>(this),
[email protected]4eaf0b32012-06-19 06:33:28652 content::Details<const string16>(&error.message()));
[email protected]9f3a59f2009-09-03 23:13:07653
[email protected]2a464a92009-08-01 17:58:35654 // This isn't really necessary, it is only used because unit tests expect to
655 // see errors get reported via this interface.
656 //
657 // TODO(aa): Need to go through unit tests and clean them up too, probably get
658 // rid of this line.
[email protected]4eaf0b32012-06-19 06:33:28659 ExtensionErrorReporter::GetInstance()->ReportError(
660 error.message(), false); // quiet
[email protected]2a464a92009-08-01 17:58:35661
[email protected]765b7ea52010-03-30 03:40:34662 if (client_)
[email protected]2a464a92009-08-01 17:58:35663 client_->OnInstallFailure(error);
[email protected]f9725c22011-05-25 14:40:33664
[email protected]bc151cf92013-02-12 04:57:26665 NotifyCrxInstallComplete(false);
[email protected]7f8f24f2012-11-15 19:40:14666
667 // Delete temporary files.
668 CleanupTempFiles();
[email protected]7577a5c52009-07-30 06:21:58669}
670
[email protected]7577a5c52009-07-30 06:21:58671void CrxInstaller::ReportSuccessFromFileThread() {
[email protected]7f8f24f2012-11-15 19:40:14672 DCHECK(installer_task_runner_->RunsTasksOnCurrentThread());
[email protected]333b1de2011-09-12 18:28:50673
674 // Tracking number of extensions installed by users
[email protected]754bc6e2012-10-22 22:26:13675 if (install_cause() == extension_misc::INSTALL_CAUSE_USER_DOWNLOAD)
[email protected]49098f702011-10-13 03:47:18676 UMA_HISTOGRAM_ENUMERATION("Extensions.ExtensionInstalled", 1, 2);
677
[email protected]14908b72011-04-20 06:54:36678 if (!BrowserThread::PostTask(
679 BrowserThread::UI, FROM_HERE,
[email protected]53612e82011-10-18 18:00:36680 base::Bind(&CrxInstaller::ReportSuccessFromUIThread, this)))
[email protected]14908b72011-04-20 06:54:36681 NOTREACHED();
[email protected]7f8f24f2012-11-15 19:40:14682
683 // Delete temporary files.
684 CleanupTempFiles();
[email protected]2a464a92009-08-01 17:58:35685}
686
687void CrxInstaller::ReportSuccessFromUIThread() {
[email protected]ca4b5fa32010-10-09 12:42:18688 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]2a464a92009-08-01 17:58:35689
[email protected]b80ec462012-10-30 18:53:00690 if (!frontend_weak_.get() || frontend_weak_->browser_terminating())
[email protected]14908b72011-04-20 06:54:36691 return;
692
[email protected]b86b9ee2013-03-01 01:58:29693 if (!update_from_settings_page_) {
694 // If there is a client, tell the client about installation.
695 if (client_)
696 client_->OnInstallSuccess(extension_.get(), install_icon_.get());
[email protected]2a464a92009-08-01 17:58:35697
[email protected]b86b9ee2013-03-01 01:58:29698 // We update the extension's granted permissions if the user already
699 // approved the install (client_ is non NULL), or we are allowed to install
700 // this silently.
701 if (client_ || allow_silent_install_) {
702 PermissionsUpdater perms_updater(profile());
[email protected]009633c2013-03-07 22:08:28703 perms_updater.GrantActivePermissions(extension_);
[email protected]b86b9ee2013-03-01 01:58:29704 }
[email protected]c333e792012-01-06 16:57:39705 }
[email protected]0d3e4a22011-06-23 19:02:52706
[email protected]bc151cf92013-02-12 04:57:26707 // Install the extension if it's not blacklisted, but notify either way.
708 base::Closure on_success =
709 base::Bind(&ExtensionService::OnExtensionInstalled,
710 frontend_weak_,
711 extension_,
712 page_ordinal_,
713 has_requirement_errors_,
714 install_wait_for_idle_);
715 if (bypass_blacklist_for_test_) {
716 HandleIsBlacklistedResponse(on_success, false);
717 } else {
718 ExtensionSystem::Get(profile_)->blacklist()->IsBlacklisted(
719 extension_->id(),
720 base::Bind(&CrxInstaller::HandleIsBlacklistedResponse,
721 this,
722 on_success));
723 }
[email protected]7577a5c52009-07-30 06:21:58724}
[email protected]f9725c22011-05-25 14:40:33725
[email protected]bc151cf92013-02-12 04:57:26726void CrxInstaller::HandleIsBlacklistedResponse(
727 const base::Closure& on_success,
728 bool is_blacklisted) {
729 if (is_blacklisted) {
730 string16 error =
731 l10n_util::GetStringFUTF16(IDS_EXTENSION_IS_BLACKLISTED,
732 UTF8ToUTF16(extension_->name()));
733 make_scoped_ptr(ExtensionInstallUI::Create(profile()))->OnInstallFailure(
734 extensions::CrxInstallerError(error));
735 // Show error via reporter to make tests happy.
736 ExtensionErrorReporter::GetInstance()->ReportError(error, false); // quiet
[email protected]ac875372013-02-28 04:36:09737 UMA_HISTOGRAM_ENUMERATION("ExtensionBlacklist.BlockCRX",
738 extension_->location(), Manifest::NUM_LOCATIONS);
[email protected]bc151cf92013-02-12 04:57:26739 } else {
740 on_success.Run();
741 }
742 NotifyCrxInstallComplete(!is_blacklisted);
743}
744
745void CrxInstaller::NotifyCrxInstallComplete(bool success) {
[email protected]f9725c22011-05-25 14:40:33746 // Some users (such as the download shelf) need to know when a
747 // CRXInstaller is done. Listening for the EXTENSION_* events
748 // is problematic because they don't know anything about the
[email protected]84f4dc02011-11-29 21:58:26749 // extension before it is unpacked, so they cannot filter based
[email protected]f9725c22011-05-25 14:40:33750 // on the extension.
[email protected]ad50def52011-10-19 23:17:07751 content::NotificationService::current()->Notify(
[email protected]432115822011-07-10 15:52:27752 chrome::NOTIFICATION_CRX_INSTALLER_DONE,
[email protected]6c2381d2011-10-19 02:52:53753 content::Source<CrxInstaller>(this),
[email protected]bc151cf92013-02-12 04:57:26754 content::Details<const Extension>(success ? extension_.get() : NULL));
755
[email protected]b86b9ee2013-03-01 01:58:29756 if (success)
757 ConfirmReEnable();
758
[email protected]f9725c22011-05-25 14:40:33759}
[email protected]bf3d9df2012-07-24 23:20:27760
[email protected]7f8f24f2012-11-15 19:40:14761void CrxInstaller::CleanupTempFiles() {
762 if (!installer_task_runner_->RunsTasksOnCurrentThread()) {
763 if (!installer_task_runner_->PostTask(
764 FROM_HERE,
765 base::Bind(&CrxInstaller::CleanupTempFiles, this))) {
766 NOTREACHED();
767 }
768 return;
769 }
770
771 // Delete the temp directory and crx file as necessary.
772 if (!temp_dir_.value().empty()) {
773 extension_file_util::DeleteFile(temp_dir_, true);
[email protected]650b2d52013-02-10 03:41:45774 temp_dir_ = base::FilePath();
[email protected]7f8f24f2012-11-15 19:40:14775 }
776
777 if (delete_source_ && !source_file_.value().empty()) {
778 extension_file_util::DeleteFile(source_file_, false);
[email protected]650b2d52013-02-10 03:41:45779 source_file_ = base::FilePath();
[email protected]7f8f24f2012-11-15 19:40:14780 }
781}
782
[email protected]b86b9ee2013-03-01 01:58:29783void CrxInstaller::CheckUpdateFromSettingsPage() {
784 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
785
786 if (!frontend_weak_.get() || frontend_weak_->browser_terminating())
787 return;
788
789 if (off_store_install_allow_reason_ != OffStoreInstallAllowedFromSettingsPage)
790 return;
791
792 const Extension* installed_extension =
793 frontend_weak_->GetInstalledExtension(extension_->id());
794 if (installed_extension) {
795 // Previous version of the extension exists.
796 update_from_settings_page_ = true;
797 expected_id_ = installed_extension->id();
798 install_source_ = installed_extension->location();
799 install_cause_ = extension_misc::INSTALL_CAUSE_UPDATE;
800 }
801}
802
803void CrxInstaller::ConfirmReEnable() {
804 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
805
806 if (!frontend_weak_.get() || frontend_weak_->browser_terminating())
807 return;
808
809 if (!update_from_settings_page_)
810 return;
811
812 extensions::ExtensionPrefs* prefs = frontend_weak_->extension_prefs();
813 if (!prefs->DidExtensionEscalatePermissions(extension_->id()))
814 return;
815
816 if (client_) {
817 AddRef(); // Balanced in InstallUIProceed() and InstallUIAbort().
818 client_->ConfirmReEnable(this, extension_.get());
819 }
820}
821
[email protected]bf3d9df2012-07-24 23:20:27822} // namespace extensions