| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/extensions/crx_installer.h" | 5 #include "chrome/browser/extensions/crx_installer.h" |
| 6 | 6 |
| 7 #include <map> | 7 #include <map> |
| 8 #include <set> | 8 #include <set> |
| 9 | 9 |
| 10 #include "base/bind.h" | 10 #include "base/bind.h" |
| (...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 165 BrowserThread::FILE, FROM_HERE, | 165 BrowserThread::FILE, FROM_HERE, |
| 166 base::Bind(&CrxInstaller::ConvertUserScriptOnFileThread, this))) | 166 base::Bind(&CrxInstaller::ConvertUserScriptOnFileThread, this))) |
| 167 NOTREACHED(); | 167 NOTREACHED(); |
| 168 } | 168 } |
| 169 | 169 |
| 170 void CrxInstaller::ConvertUserScriptOnFileThread() { | 170 void CrxInstaller::ConvertUserScriptOnFileThread() { |
| 171 string16 error; | 171 string16 error; |
| 172 scoped_refptr<Extension> extension = | 172 scoped_refptr<Extension> extension = |
| 173 ConvertUserScriptToExtension(source_file_, download_url_, &error); | 173 ConvertUserScriptToExtension(source_file_, download_url_, &error); |
| 174 if (!extension) { | 174 if (!extension) { |
| 175 ReportFailureFromFileThread(error); | 175 ReportFailureFromFileThread(CrxInstallerError(error)); |
| 176 return; | 176 return; |
| 177 } | 177 } |
| 178 | 178 |
| 179 OnUnpackSuccess(extension->path(), extension->path(), NULL, extension); | 179 OnUnpackSuccess(extension->path(), extension->path(), NULL, extension); |
| 180 } | 180 } |
| 181 | 181 |
| 182 void CrxInstaller::InstallWebApp(const WebApplicationInfo& web_app) { | 182 void CrxInstaller::InstallWebApp(const WebApplicationInfo& web_app) { |
| 183 if (!BrowserThread::PostTask( | 183 if (!BrowserThread::PostTask( |
| 184 BrowserThread::FILE, FROM_HERE, | 184 BrowserThread::FILE, FROM_HERE, |
| 185 base::Bind(&CrxInstaller::ConvertWebAppOnFileThread, this, web_app))) | 185 base::Bind(&CrxInstaller::ConvertWebAppOnFileThread, this, web_app))) |
| 186 NOTREACHED(); | 186 NOTREACHED(); |
| 187 } | 187 } |
| 188 | 188 |
| 189 void CrxInstaller::ConvertWebAppOnFileThread( | 189 void CrxInstaller::ConvertWebAppOnFileThread( |
| 190 const WebApplicationInfo& web_app) { | 190 const WebApplicationInfo& web_app) { |
| 191 string16 error; | 191 string16 error; |
| 192 scoped_refptr<Extension> extension( | 192 scoped_refptr<Extension> extension( |
| 193 ConvertWebAppToExtension(web_app, base::Time::Now())); | 193 ConvertWebAppToExtension(web_app, base::Time::Now())); |
| 194 if (!extension) { | 194 if (!extension) { |
| 195 // Validation should have stopped any potential errors before getting here. | 195 // Validation should have stopped any potential errors before getting here. |
| 196 NOTREACHED() << "Could not convert web app to extension."; | 196 NOTREACHED() << "Could not convert web app to extension."; |
| 197 return; | 197 return; |
| 198 } | 198 } |
| 199 | 199 |
| 200 // TODO(aa): conversion data gets lost here :( | 200 // TODO(aa): conversion data gets lost here :( |
| 201 | 201 |
| 202 OnUnpackSuccess(extension->path(), extension->path(), NULL, extension); | 202 OnUnpackSuccess(extension->path(), extension->path(), NULL, extension); |
| 203 } | 203 } |
| 204 | 204 |
| 205 bool CrxInstaller::AllowInstall(const Extension* extension, | 205 CrxInstallerError CrxInstaller::AllowInstall(const Extension* extension) { |
| 206 string16* error) { | |
| 207 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 206 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
| 208 DCHECK(error); | |
| 209 | 207 |
| 210 // Make sure the expected ID matches if one was supplied or if we want to | 208 // Make sure the expected ID matches if one was supplied or if we want to |
| 211 // bypass the prompt. | 209 // bypass the prompt. |
| 212 if ((approved_ || !expected_id_.empty()) && | 210 if ((approved_ || !expected_id_.empty()) && |
| 213 expected_id_ != extension->id()) { | 211 expected_id_ != extension->id()) { |
| 214 *error = l10n_util::GetStringFUTF16(IDS_EXTENSION_INSTALL_UNEXPECTED_ID, | 212 return CrxInstallerError( |
| 215 ASCIIToUTF16(expected_id_), | 213 l10n_util::GetStringFUTF16(IDS_EXTENSION_INSTALL_UNEXPECTED_ID, |
| 216 ASCIIToUTF16(extension->id())); | 214 ASCIIToUTF16(expected_id_), |
| 217 return false; | 215 ASCIIToUTF16(extension->id()))); |
| 218 } | 216 } |
| 219 | 217 |
| 220 if (expected_version_.get() && | 218 if (expected_version_.get() && |
| 221 !expected_version_->Equals(*extension->version())) { | 219 !expected_version_->Equals(*extension->version())) { |
| 222 *error = l10n_util::GetStringFUTF16( | 220 return CrxInstallerError( |
| 223 IDS_EXTENSION_INSTALL_UNEXPECTED_VERSION, | 221 l10n_util::GetStringFUTF16( |
| 224 ASCIIToUTF16(expected_version_->GetString()), | 222 IDS_EXTENSION_INSTALL_UNEXPECTED_VERSION, |
| 225 ASCIIToUTF16(extension->version()->GetString())); | 223 ASCIIToUTF16(expected_version_->GetString()), |
| 226 return false; | 224 ASCIIToUTF16(extension->version()->GetString()))); |
| 227 } | 225 } |
| 228 | 226 |
| 229 // Make sure the manifests match if we want to bypass the prompt. | 227 // Make sure the manifests match if we want to bypass the prompt. |
| 230 if (approved_ && | 228 if (approved_ && |
| 231 (!expected_manifest_.get() || | 229 (!expected_manifest_.get() || |
| 232 !expected_manifest_->Equals(original_manifest_.get()))) { | 230 !expected_manifest_->Equals(original_manifest_.get()))) { |
| 233 *error = l10n_util::GetStringUTF16(IDS_EXTENSION_MANIFEST_INVALID); | 231 return CrxInstallerError( |
| 234 return false; | 232 l10n_util::GetStringUTF16(IDS_EXTENSION_MANIFEST_INVALID)); |
| 235 } | 233 } |
| 236 | 234 |
| 237 // The checks below are skipped for themes and external installs. | 235 // The checks below are skipped for themes and external installs. |
| 238 // TODO(pamg): After ManagementPolicy refactoring is complete, remove this | 236 // TODO(pamg): After ManagementPolicy refactoring is complete, remove this |
| 239 // and other uses of install_source_ that are no longer needed now that the | 237 // and other uses of install_source_ that are no longer needed now that the |
| 240 // SandboxedExtensionUnpacker sets extension->location. | 238 // SandboxedExtensionUnpacker sets extension->location. |
| 241 if (extension->is_theme() || Extension::IsExternalLocation(install_source_)) | 239 if (extension->is_theme() || Extension::IsExternalLocation(install_source_)) |
| 242 return true; | 240 return CrxInstallerError(); |
| 243 | 241 |
| 244 if (!extensions_enabled_) { | 242 if (!extensions_enabled_) { |
| 245 *error = l10n_util::GetStringUTF16(IDS_EXTENSION_INSTALL_NOT_ENABLED); | 243 return CrxInstallerError( |
| 246 return false; | 244 l10n_util::GetStringUTF16(IDS_EXTENSION_INSTALL_NOT_ENABLED)); |
| 247 } | 245 } |
| 248 | 246 |
| 249 if (install_cause_ == extension_misc::INSTALL_CAUSE_USER_DOWNLOAD) { | 247 if (install_cause_ == extension_misc::INSTALL_CAUSE_USER_DOWNLOAD) { |
| 250 if (extensions::switch_utils::IsEasyOffStoreInstallEnabled()) { | 248 if (extensions::switch_utils::IsEasyOffStoreInstallEnabled()) { |
| 251 const char* kHistogramName = "Extensions.OffStoreInstallDecisionEasy"; | 249 const char* kHistogramName = "Extensions.OffStoreInstallDecisionEasy"; |
| 252 if (is_gallery_install()) { | 250 if (is_gallery_install()) { |
| 253 UMA_HISTOGRAM_ENUMERATION(kHistogramName, OnStoreInstall, | 251 UMA_HISTOGRAM_ENUMERATION(kHistogramName, OnStoreInstall, |
| 254 NumOffStoreInstallDecision); | 252 NumOffStoreInstallDecision); |
| 255 } else { | 253 } else { |
| 256 UMA_HISTOGRAM_ENUMERATION(kHistogramName, OffStoreInstallAllowed, | 254 UMA_HISTOGRAM_ENUMERATION(kHistogramName, OffStoreInstallAllowed, |
| 257 NumOffStoreInstallDecision); | 255 NumOffStoreInstallDecision); |
| 258 } | 256 } |
| 259 } else { | 257 } else { |
| 260 const char* kHistogramName = "Extensions.OffStoreInstallDecisionHard"; | 258 const char* kHistogramName = "Extensions.OffStoreInstallDecisionHard"; |
| 261 if (is_gallery_install()) { | 259 if (is_gallery_install()) { |
| 262 UMA_HISTOGRAM_ENUMERATION(kHistogramName, OnStoreInstall, | 260 UMA_HISTOGRAM_ENUMERATION(kHistogramName, OnStoreInstall, |
| 263 NumOffStoreInstallDecision); | 261 NumOffStoreInstallDecision); |
| 264 } else if (off_store_install_allow_reason_ != OffStoreInstallDisallowed) { | 262 } else if (off_store_install_allow_reason_ != OffStoreInstallDisallowed) { |
| 265 UMA_HISTOGRAM_ENUMERATION(kHistogramName, OffStoreInstallAllowed, | 263 UMA_HISTOGRAM_ENUMERATION(kHistogramName, OffStoreInstallAllowed, |
| 266 NumOffStoreInstallDecision); | 264 NumOffStoreInstallDecision); |
| 267 UMA_HISTOGRAM_ENUMERATION("Extensions.OffStoreInstallAllowReason", | 265 UMA_HISTOGRAM_ENUMERATION("Extensions.OffStoreInstallAllowReason", |
| 268 off_store_install_allow_reason_, | 266 off_store_install_allow_reason_, |
| 269 NumOffStoreInstallAllowReasons); | 267 NumOffStoreInstallAllowReasons); |
| 270 } else { | 268 } else { |
| 271 UMA_HISTOGRAM_ENUMERATION(kHistogramName, OffStoreInstallDisallowed, | 269 UMA_HISTOGRAM_ENUMERATION(kHistogramName, OffStoreInstallDisallowed, |
| 272 NumOffStoreInstallDecision); | 270 NumOffStoreInstallDecision); |
| 273 *error = l10n_util::GetStringUTF16( | |
| 274 IDS_EXTENSION_INSTALL_DISALLOWED_ON_SITE); | |
| 275 // Don't delete source in this case so that the user can install | 271 // Don't delete source in this case so that the user can install |
| 276 // manually if they want. | 272 // manually if they want. |
| 277 delete_source_ = false; | 273 delete_source_ = false; |
| 278 did_handle_successfully_ = false; | 274 did_handle_successfully_ = false; |
| 279 return false; | 275 |
| 276 return CrxInstallerError( |
| 277 CrxInstallerError::ERROR_OFF_STORE, |
| 278 l10n_util::GetStringUTF16( |
| 279 IDS_EXTENSION_INSTALL_DISALLOWED_ON_SITE)); |
| 280 } | 280 } |
| 281 } | 281 } |
| 282 } | 282 } |
| 283 | 283 |
| 284 if (extension_->is_app()) { | 284 if (extension_->is_app()) { |
| 285 // If the app was downloaded, apps_require_extension_mime_type_ | 285 // If the app was downloaded, apps_require_extension_mime_type_ |
| 286 // will be set. In this case, check that it was served with the | 286 // will be set. In this case, check that it was served with the |
| 287 // right mime type. Make an exception for file URLs, which come | 287 // right mime type. Make an exception for file URLs, which come |
| 288 // from the users computer and have no headers. | 288 // from the users computer and have no headers. |
| 289 if (!download_url_.SchemeIsFile() && | 289 if (!download_url_.SchemeIsFile() && |
| 290 apps_require_extension_mime_type_ && | 290 apps_require_extension_mime_type_ && |
| 291 original_mime_type_ != Extension::kMimeType) { | 291 original_mime_type_ != Extension::kMimeType) { |
| 292 *error = l10n_util::GetStringFUTF16( | 292 return CrxInstallerError( |
| 293 IDS_EXTENSION_INSTALL_INCORRECT_APP_CONTENT_TYPE, | 293 l10n_util::GetStringFUTF16( |
| 294 ASCIIToUTF16(Extension::kMimeType)); | 294 IDS_EXTENSION_INSTALL_INCORRECT_APP_CONTENT_TYPE, |
| 295 return false; | 295 ASCIIToUTF16(Extension::kMimeType))); |
| 296 } | 296 } |
| 297 | 297 |
| 298 // If the client_ is NULL, then the app is either being installed via | 298 // If the client_ is NULL, then the app is either being installed via |
| 299 // an internal mechanism like sync, external_extensions, or default apps. | 299 // an internal mechanism like sync, external_extensions, or default apps. |
| 300 // In that case, we don't want to enforce things like the install origin. | 300 // In that case, we don't want to enforce things like the install origin. |
| 301 if (!is_gallery_install() && client_) { | 301 if (!is_gallery_install() && client_) { |
| 302 // For apps with a gallery update URL, require that they be installed | 302 // For apps with a gallery update URL, require that they be installed |
| 303 // from the gallery. | 303 // from the gallery. |
| 304 // TODO(erikkay) Apply this rule for paid extensions and themes as well. | 304 // TODO(erikkay) Apply this rule for paid extensions and themes as well. |
| 305 if (extension->UpdatesFromGallery()) { | 305 if (extension->UpdatesFromGallery()) { |
| 306 *error = l10n_util::GetStringFUTF16( | 306 return CrxInstallerError( |
| 307 IDS_EXTENSION_DISALLOW_NON_DOWNLOADED_GALLERY_INSTALLS, | 307 l10n_util::GetStringFUTF16( |
| 308 l10n_util::GetStringUTF16(IDS_EXTENSION_WEB_STORE_TITLE)); | 308 IDS_EXTENSION_DISALLOW_NON_DOWNLOADED_GALLERY_INSTALLS, |
| 309 return false; | 309 l10n_util::GetStringUTF16(IDS_EXTENSION_WEB_STORE_TITLE))); |
| 310 } | 310 } |
| 311 | 311 |
| 312 // For self-hosted apps, verify that the entire extent is on the same | 312 // For self-hosted apps, verify that the entire extent is on the same |
| 313 // host (or a subdomain of the host) the download happened from. There's | 313 // host (or a subdomain of the host) the download happened from. There's |
| 314 // no way for us to verify that the app controls any other hosts. | 314 // no way for us to verify that the app controls any other hosts. |
| 315 URLPattern pattern(UserScript::kValidUserScriptSchemes); | 315 URLPattern pattern(UserScript::kValidUserScriptSchemes); |
| 316 pattern.SetHost(download_url_.host()); | 316 pattern.SetHost(download_url_.host()); |
| 317 pattern.SetMatchSubdomains(true); | 317 pattern.SetMatchSubdomains(true); |
| 318 | 318 |
| 319 URLPatternSet patterns = extension_->web_extent(); | 319 URLPatternSet patterns = extension_->web_extent(); |
| 320 for (URLPatternSet::const_iterator i = patterns.begin(); | 320 for (URLPatternSet::const_iterator i = patterns.begin(); |
| 321 i != patterns.end(); ++i) { | 321 i != patterns.end(); ++i) { |
| 322 if (!pattern.MatchesHost(i->host())) { | 322 if (!pattern.MatchesHost(i->host())) { |
| 323 *error = l10n_util::GetStringUTF16( | 323 return CrxInstallerError( |
| 324 IDS_EXTENSION_INSTALL_INCORRECT_INSTALL_HOST); | 324 l10n_util::GetStringUTF16( |
| 325 return false; | 325 IDS_EXTENSION_INSTALL_INCORRECT_INSTALL_HOST)); |
| 326 } | 326 } |
| 327 } | 327 } |
| 328 } | 328 } |
| 329 } | 329 } |
| 330 | 330 |
| 331 return true; | 331 return CrxInstallerError(); |
| 332 } | 332 } |
| 333 | 333 |
| 334 void CrxInstaller::OnUnpackFailure(const string16& error_message) { | 334 void CrxInstaller::OnUnpackFailure(const string16& error_message) { |
| 335 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 335 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
| 336 | 336 |
| 337 UMA_HISTOGRAM_ENUMERATION("Extensions.UnpackFailureInstallSource", | 337 UMA_HISTOGRAM_ENUMERATION("Extensions.UnpackFailureInstallSource", |
| 338 install_source(), Extension::NUM_LOCATIONS); | 338 install_source(), Extension::NUM_LOCATIONS); |
| 339 | 339 |
| 340 UMA_HISTOGRAM_ENUMERATION("Extensions.UnpackFailureInstallCause", | 340 UMA_HISTOGRAM_ENUMERATION("Extensions.UnpackFailureInstallCause", |
| 341 install_cause(), | 341 install_cause(), |
| 342 extension_misc::NUM_INSTALL_CAUSES); | 342 extension_misc::NUM_INSTALL_CAUSES); |
| 343 | 343 |
| 344 ReportFailureFromFileThread(error_message); | 344 ReportFailureFromFileThread(CrxInstallerError(error_message)); |
| 345 } | 345 } |
| 346 | 346 |
| 347 void CrxInstaller::OnUnpackSuccess(const FilePath& temp_dir, | 347 void CrxInstaller::OnUnpackSuccess(const FilePath& temp_dir, |
| 348 const FilePath& extension_dir, | 348 const FilePath& extension_dir, |
| 349 const DictionaryValue* original_manifest, | 349 const DictionaryValue* original_manifest, |
| 350 const Extension* extension) { | 350 const Extension* extension) { |
| 351 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 351 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
| 352 | 352 |
| 353 UMA_HISTOGRAM_ENUMERATION("Extensions.UnpackSuccessInstallSource", | 353 UMA_HISTOGRAM_ENUMERATION("Extensions.UnpackSuccessInstallSource", |
| 354 install_source(), Extension::NUM_LOCATIONS); | 354 install_source(), Extension::NUM_LOCATIONS); |
| 355 | 355 |
| 356 | 356 |
| 357 UMA_HISTOGRAM_ENUMERATION("Extensions.UnpackSuccessInstallCause", | 357 UMA_HISTOGRAM_ENUMERATION("Extensions.UnpackSuccessInstallCause", |
| 358 install_cause(), | 358 install_cause(), |
| 359 extension_misc::NUM_INSTALL_CAUSES); | 359 extension_misc::NUM_INSTALL_CAUSES); |
| 360 | 360 |
| 361 // Note: We take ownership of |extension| and |temp_dir|. | 361 // Note: We take ownership of |extension| and |temp_dir|. |
| 362 extension_ = extension; | 362 extension_ = extension; |
| 363 temp_dir_ = temp_dir; | 363 temp_dir_ = temp_dir; |
| 364 | 364 |
| 365 if (original_manifest) | 365 if (original_manifest) |
| 366 original_manifest_.reset(original_manifest->DeepCopy()); | 366 original_manifest_.reset(original_manifest->DeepCopy()); |
| 367 | 367 |
| 368 // We don't have to delete the unpack dir explicity since it is a child of | 368 // We don't have to delete the unpack dir explicity since it is a child of |
| 369 // the temp dir. | 369 // the temp dir. |
| 370 unpacked_extension_root_ = extension_dir; | 370 unpacked_extension_root_ = extension_dir; |
| 371 | 371 |
| 372 string16 error; | 372 CrxInstallerError error = AllowInstall(extension); |
| 373 if (!AllowInstall(extension, &error)) { | 373 if (error.type() != CrxInstallerError::ERROR_NONE) { |
| 374 ReportFailureFromFileThread(error); | 374 ReportFailureFromFileThread(error); |
| 375 return; | 375 return; |
| 376 } | 376 } |
| 377 | 377 |
| 378 if (client_) { | 378 if (client_) { |
| 379 Extension::DecodeIcon(extension_.get(), | 379 Extension::DecodeIcon(extension_.get(), |
| 380 ExtensionIconSet::EXTENSION_ICON_LARGE, | 380 ExtensionIconSet::EXTENSION_ICON_LARGE, |
| 381 ExtensionIconSet::MATCH_BIGGER, | 381 ExtensionIconSet::MATCH_BIGGER, |
| 382 &install_icon_); | 382 &install_icon_); |
| 383 } | 383 } |
| 384 | 384 |
| 385 if (!BrowserThread::PostTask( | 385 if (!BrowserThread::PostTask( |
| 386 BrowserThread::UI, FROM_HERE, | 386 BrowserThread::UI, FROM_HERE, |
| 387 base::Bind(&CrxInstaller::ConfirmInstall, this))) | 387 base::Bind(&CrxInstaller::ConfirmInstall, this))) |
| 388 NOTREACHED(); | 388 NOTREACHED(); |
| 389 } | 389 } |
| 390 | 390 |
| 391 void CrxInstaller::ConfirmInstall() { | 391 void CrxInstaller::ConfirmInstall() { |
| 392 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 392 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 393 if (!frontend_weak_.get()) | 393 if (!frontend_weak_.get()) |
| 394 return; | 394 return; |
| 395 | 395 |
| 396 if (frontend_weak_->extension_prefs() | 396 if (frontend_weak_->extension_prefs() |
| 397 ->IsExtensionBlacklisted(extension_->id())) { | 397 ->IsExtensionBlacklisted(extension_->id())) { |
| 398 VLOG(1) << "This extension: " << extension_->id() | 398 VLOG(1) << "This extension: " << extension_->id() |
| 399 << " is blacklisted. Install failed."; | 399 << " is blacklisted. Install failed."; |
| 400 ReportFailureFromUIThread( | 400 ReportFailureFromUIThread( |
| 401 l10n_util::GetStringUTF16(IDS_EXTENSION_CANT_INSTALL_BLACKLISTED)); | 401 CrxInstallerError( |
| 402 l10n_util::GetStringUTF16(IDS_EXTENSION_CANT_INSTALL_BLACKLISTED))); |
| 402 return; | 403 return; |
| 403 } | 404 } |
| 404 | 405 |
| 405 string16 error; | 406 string16 error; |
| 406 if (!ExtensionSystem::Get(profile_)->management_policy()->UserMayLoad( | 407 if (!ExtensionSystem::Get(profile_)->management_policy()->UserMayLoad( |
| 407 extension_, &error)) { | 408 extension_, &error)) { |
| 408 ReportFailureFromUIThread(error); | 409 ReportFailureFromUIThread(CrxInstallerError(error)); |
| 409 return; | 410 return; |
| 410 } | 411 } |
| 411 | 412 |
| 412 GURL overlapping_url; | 413 GURL overlapping_url; |
| 413 const Extension* overlapping_extension = | 414 const Extension* overlapping_extension = |
| 414 frontend_weak_->extensions()-> | 415 frontend_weak_->extensions()-> |
| 415 GetHostedAppByOverlappingWebExtent(extension_->web_extent()); | 416 GetHostedAppByOverlappingWebExtent(extension_->web_extent()); |
| 416 if (overlapping_extension && | 417 if (overlapping_extension && |
| 417 overlapping_extension->id() != extension_->id()) { | 418 overlapping_extension->id() != extension_->id()) { |
| 418 ReportFailureFromUIThread(l10n_util::GetStringFUTF16( | 419 ReportFailureFromUIThread( |
| 419 IDS_EXTENSION_OVERLAPPING_WEB_EXTENT, | 420 CrxInstallerError( |
| 420 UTF8ToUTF16(overlapping_extension->name()))); | 421 l10n_util::GetStringFUTF16( |
| 422 IDS_EXTENSION_OVERLAPPING_WEB_EXTENT, |
| 423 UTF8ToUTF16(overlapping_extension->name())))); |
| 421 return; | 424 return; |
| 422 } | 425 } |
| 423 | 426 |
| 424 current_version_ = | 427 current_version_ = |
| 425 frontend_weak_->extension_prefs()->GetVersionString(extension_->id()); | 428 frontend_weak_->extension_prefs()->GetVersionString(extension_->id()); |
| 426 | 429 |
| 427 if (client_ && (!allow_silent_install_ || !approved_)) { | 430 if (client_ && (!allow_silent_install_ || !approved_)) { |
| 428 AddRef(); // Balanced in Proceed() and Abort(). | 431 AddRef(); // Balanced in Proceed() and Abort(). |
| 429 client_->ConfirmInstall(this, extension_.get()); | 432 client_->ConfirmInstall(this, extension_.get()); |
| 430 } else { | 433 } else { |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 467 } | 470 } |
| 468 | 471 |
| 469 void CrxInstaller::CompleteInstall() { | 472 void CrxInstaller::CompleteInstall() { |
| 470 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 473 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
| 471 | 474 |
| 472 if (!current_version_.empty()) { | 475 if (!current_version_.empty()) { |
| 473 scoped_ptr<Version> current_version( | 476 scoped_ptr<Version> current_version( |
| 474 Version::GetVersionFromString(current_version_)); | 477 Version::GetVersionFromString(current_version_)); |
| 475 if (current_version->CompareTo(*(extension_->version())) > 0) { | 478 if (current_version->CompareTo(*(extension_->version())) > 0) { |
| 476 ReportFailureFromFileThread( | 479 ReportFailureFromFileThread( |
| 477 l10n_util::GetStringUTF16(IDS_EXTENSION_CANT_DOWNGRADE_VERSION)); | 480 CrxInstallerError( |
| 481 l10n_util::GetStringUTF16(IDS_EXTENSION_CANT_DOWNGRADE_VERSION))); |
| 478 return; | 482 return; |
| 479 } | 483 } |
| 480 } | 484 } |
| 481 | 485 |
| 482 // See how long extension install paths are. This is important on | 486 // See how long extension install paths are. This is important on |
| 483 // windows, because file operations may fail if the path to a file | 487 // windows, because file operations may fail if the path to a file |
| 484 // exceeds a small constant. See crbug.com/69693 . | 488 // exceeds a small constant. See crbug.com/69693 . |
| 485 UMA_HISTOGRAM_CUSTOM_COUNTS( | 489 UMA_HISTOGRAM_CUSTOM_COUNTS( |
| 486 "Extensions.CrxInstallDirPathLength", | 490 "Extensions.CrxInstallDirPathLength", |
| 487 install_directory_.value().length(), 0, 500, 100); | 491 install_directory_.value().length(), 0, 500, 100); |
| 488 | 492 |
| 489 FilePath version_dir = extension_file_util::InstallExtension( | 493 FilePath version_dir = extension_file_util::InstallExtension( |
| 490 unpacked_extension_root_, | 494 unpacked_extension_root_, |
| 491 extension_->id(), | 495 extension_->id(), |
| 492 extension_->VersionString(), | 496 extension_->VersionString(), |
| 493 install_directory_); | 497 install_directory_); |
| 494 if (version_dir.empty()) { | 498 if (version_dir.empty()) { |
| 495 ReportFailureFromFileThread( | 499 ReportFailureFromFileThread( |
| 496 l10n_util::GetStringUTF16( | 500 CrxInstallerError( |
| 497 IDS_EXTENSION_MOVE_DIRECTORY_TO_PROFILE_FAILED)); | 501 l10n_util::GetStringUTF16( |
| 502 IDS_EXTENSION_MOVE_DIRECTORY_TO_PROFILE_FAILED))); |
| 498 return; | 503 return; |
| 499 } | 504 } |
| 500 | 505 |
| 501 // This is lame, but we must reload the extension because absolute paths | 506 // This is lame, but we must reload the extension because absolute paths |
| 502 // inside the content scripts are established inside InitFromValue() and we | 507 // inside the content scripts are established inside InitFromValue() and we |
| 503 // just moved the extension. | 508 // just moved the extension. |
| 504 // TODO(aa): All paths to resources inside extensions should be created | 509 // TODO(aa): All paths to resources inside extensions should be created |
| 505 // lazily and based on the Extension's root path at that moment. | 510 // lazily and based on the Extension's root path at that moment. |
| 506 // TODO(rdevlin.cronin): Continue removing std::string errors and replacing | 511 // TODO(rdevlin.cronin): Continue removing std::string errors and replacing |
| 507 // with string16 | 512 // with string16 |
| 508 std::string error; | 513 std::string error; |
| 509 extension_ = extension_file_util::LoadExtension( | 514 extension_ = extension_file_util::LoadExtension( |
| 510 version_dir, | 515 version_dir, |
| 511 install_source_, | 516 install_source_, |
| 512 extension_->creation_flags() | Extension::REQUIRE_KEY, | 517 extension_->creation_flags() | Extension::REQUIRE_KEY, |
| 513 &error); | 518 &error); |
| 514 CHECK(error.empty()) << error; | 519 CHECK(error.empty()) << error; |
| 515 | 520 |
| 516 ReportSuccessFromFileThread(); | 521 ReportSuccessFromFileThread(); |
| 517 } | 522 } |
| 518 | 523 |
| 519 void CrxInstaller::ReportFailureFromFileThread(const string16& error) { | 524 void CrxInstaller::ReportFailureFromFileThread(const CrxInstallerError& error) { |
| 520 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 525 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
| 521 if (!BrowserThread::PostTask( | 526 if (!BrowserThread::PostTask( |
| 522 BrowserThread::UI, FROM_HERE, | 527 BrowserThread::UI, FROM_HERE, |
| 523 base::Bind(&CrxInstaller::ReportFailureFromUIThread, this, error))) | 528 base::Bind(&CrxInstaller::ReportFailureFromUIThread, this, error))) { |
| 524 NOTREACHED(); | 529 NOTREACHED(); |
| 530 } |
| 525 } | 531 } |
| 526 | 532 |
| 527 void CrxInstaller::ReportFailureFromUIThread(const string16& error) { | 533 void CrxInstaller::ReportFailureFromUIThread(const CrxInstallerError& error) { |
| 528 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 534 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 529 | 535 |
| 530 content::NotificationService* service = | 536 content::NotificationService* service = |
| 531 content::NotificationService::current(); | 537 content::NotificationService::current(); |
| 532 service->Notify(chrome::NOTIFICATION_EXTENSION_INSTALL_ERROR, | 538 service->Notify(chrome::NOTIFICATION_EXTENSION_INSTALL_ERROR, |
| 533 content::Source<CrxInstaller>(this), | 539 content::Source<CrxInstaller>(this), |
| 534 content::Details<const string16>(&error)); | 540 content::Details<const string16>(&error.message())); |
| 535 | 541 |
| 536 // This isn't really necessary, it is only used because unit tests expect to | 542 // This isn't really necessary, it is only used because unit tests expect to |
| 537 // see errors get reported via this interface. | 543 // see errors get reported via this interface. |
| 538 // | 544 // |
| 539 // TODO(aa): Need to go through unit tests and clean them up too, probably get | 545 // TODO(aa): Need to go through unit tests and clean them up too, probably get |
| 540 // rid of this line. | 546 // rid of this line. |
| 541 ExtensionErrorReporter::GetInstance()->ReportError(error, false); // quiet | 547 ExtensionErrorReporter::GetInstance()->ReportError( |
| 548 error.message(), false); // quiet |
| 542 | 549 |
| 543 if (client_) | 550 if (client_) |
| 544 client_->OnInstallFailure(error); | 551 client_->OnInstallFailure(error); |
| 545 | 552 |
| 546 NotifyCrxInstallComplete(NULL); | 553 NotifyCrxInstallComplete(NULL); |
| 547 } | 554 } |
| 548 | 555 |
| 549 void CrxInstaller::ReportSuccessFromFileThread() { | 556 void CrxInstaller::ReportSuccessFromFileThread() { |
| 550 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 557 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
| 551 | 558 |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 605 // Some users (such as the download shelf) need to know when a | 612 // Some users (such as the download shelf) need to know when a |
| 606 // CRXInstaller is done. Listening for the EXTENSION_* events | 613 // CRXInstaller is done. Listening for the EXTENSION_* events |
| 607 // is problematic because they don't know anything about the | 614 // is problematic because they don't know anything about the |
| 608 // extension before it is unpacked, so they cannot filter based | 615 // extension before it is unpacked, so they cannot filter based |
| 609 // on the extension. | 616 // on the extension. |
| 610 content::NotificationService::current()->Notify( | 617 content::NotificationService::current()->Notify( |
| 611 chrome::NOTIFICATION_CRX_INSTALLER_DONE, | 618 chrome::NOTIFICATION_CRX_INSTALLER_DONE, |
| 612 content::Source<CrxInstaller>(this), | 619 content::Source<CrxInstaller>(this), |
| 613 content::Details<const Extension>(extension)); | 620 content::Details<const Extension>(extension)); |
| 614 } | 621 } |
| OLD | NEW |