172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved. 2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use of this source code is governed by a BSD-style license that can be 3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// found in the LICENSE file. 4c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 5c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/extensions/crx_installer.h" 6c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 7ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include <map> 84a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#include <set> 9513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch 10c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/file_util.h" 1121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "base/lazy_instance.h" 12ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "base/memory/scoped_temp_dir.h" 13ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "base/metrics/histogram.h" 14c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/path_service.h" 154a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#include "base/stl_util-inl.h" 163345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/stringprintf.h" 17c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/task.h" 183f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen#include "base/threading/thread_restrictions.h" 19ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "base/time.h" 20c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/utf_string_conversions.h" 213345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/version.h" 22c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/browser_process.h" 23c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/extensions/convert_user_script.h" 24201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch#include "chrome/browser/extensions/convert_web_app.h" 25c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/extensions/extension_error_reporter.h" 26ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "chrome/browser/extensions/extension_service.h" 27c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/shell_integration.h" 28c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/web_applications/web_app.h" 29c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/chrome_paths.h" 30c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/extensions/extension_constants.h" 31ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "chrome/common/extensions/extension_file_util.h" 32dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/browser/browser_thread.h" 33ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "content/common/notification_service.h" 34ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "content/common/notification_type.h" 35c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "grit/chromium_strings.h" 36c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "grit/generated_resources.h" 373345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "grit/theme_resources.h" 38c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "third_party/skia/include/core/SkBitmap.h" 3972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "ui/base/l10n/l10n_util.h" 4072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "ui/base/resource/resource_bundle.h" 41c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 42c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace { 433345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 443345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickstruct WhitelistedInstallData { 453345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick WhitelistedInstallData() {} 464a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch std::set<std::string> ids; 47ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen std::map<std::string, linked_ptr<DictionaryValue> > manifests; 483345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}; 493345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 5021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsenstatic base::LazyInstance<WhitelistedInstallData> 5121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen g_whitelisted_install_data(base::LINKER_INITIALIZED); 5221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen 53513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch} // namespace 543345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 553345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// static 563345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid CrxInstaller::SetWhitelistedInstallId(const std::string& id) { 57731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 5821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen g_whitelisted_install_data.Get().ids.insert(id); 593345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick} 603345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 613345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// static 62ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid CrxInstaller::SetWhitelistedManifest(const std::string& id, 63ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen DictionaryValue* parsed_manifest) { 64ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 65ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen WhitelistedInstallData& data = g_whitelisted_install_data.Get(); 66ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen data.manifests[id] = linked_ptr<DictionaryValue>(parsed_manifest); 67ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen} 68ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 69ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// static 70ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenconst DictionaryValue* CrxInstaller::GetWhitelistedManifest( 71ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen const std::string& id) { 72ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen WhitelistedInstallData& data = g_whitelisted_install_data.Get(); 73ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (ContainsKey(data.manifests, id)) 74ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return data.manifests[id].get(); 75ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen else 76ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return NULL; 77ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen} 78ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 79ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// static 80ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian MonsenDictionaryValue* CrxInstaller::RemoveWhitelistedManifest( 81ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen const std::string& id) { 82ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen WhitelistedInstallData& data = g_whitelisted_install_data.Get(); 83ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (ContainsKey(data.manifests, id)) { 84ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen DictionaryValue* manifest = data.manifests[id].release(); 85ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen data.manifests.erase(id); 86ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return manifest; 87ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 88ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return NULL; 89ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen} 90ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 91ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// static 924a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdochbool CrxInstaller::IsIdWhitelisted(const std::string& id) { 93513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 9421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen std::set<std::string>& ids = g_whitelisted_install_data.Get().ids; 954a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch return ContainsKey(ids, id); 964a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch} 973345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 984a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch// static 994a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdochbool CrxInstaller::ClearWhitelistedInstallId(const std::string& id) { 1004a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 10121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen std::set<std::string>& ids = g_whitelisted_install_data.Get().ids; 1024a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch if (ContainsKey(ids, id)) { 1034a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch ids.erase(id); 1043345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick return true; 1053345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick } 1063345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick return false; 107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 10921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian MonsenCrxInstaller::CrxInstaller(ExtensionService* frontend, 110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ExtensionInstallUI* client) 111201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch : install_directory_(frontend->install_directory()), 112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch install_source_(Extension::INTERNAL), 113201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch extensions_enabled_(frontend->extensions_enabled()), 114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch delete_source_(false), 115731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick is_gallery_install_(false), 116731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick create_app_shortcut_(false), 117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch frontend_(frontend), 118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch client_(client), 1193345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick apps_require_extension_mime_type_(false), 1203345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick allow_silent_install_(false) { 121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 122c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 123c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochCrxInstaller::~CrxInstaller() { 124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Delete the temp directory and crx file as necessary. Note that the 125c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // destructor might be called on any thread, so we post a task to the file 126c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // thread to make sure the delete happens there. 127c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!temp_dir_.value().empty()) { 128731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick BrowserThread::PostTask( 129731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick BrowserThread::FILE, FROM_HERE, 130dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen NewRunnableFunction( 131dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen &extension_file_util::DeleteFile, temp_dir_, true)); 132c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 133c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 134c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (delete_source_) { 135731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick BrowserThread::PostTask( 136731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick BrowserThread::FILE, FROM_HERE, 137dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen NewRunnableFunction( 138dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen &extension_file_util::DeleteFile, source_file_, false)); 139c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 140c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 141c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Make sure the UI is deleted on the ui thread. 142731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick BrowserThread::DeleteSoon(BrowserThread::UI, FROM_HERE, client_); 143c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch client_ = NULL; 144c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 145c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 146c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid CrxInstaller::InstallCrx(const FilePath& source_file) { 147c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch source_file_ = source_file; 148c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 149c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch scoped_refptr<SandboxedExtensionUnpacker> unpacker( 150c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch new SandboxedExtensionUnpacker( 151c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch source_file, 152c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch g_browser_process->resource_dispatcher_host(), 153c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch this)); 154c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 155731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick BrowserThread::PostTask( 156731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick BrowserThread::FILE, FROM_HERE, 157c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NewRunnableMethod( 158c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch unpacker.get(), &SandboxedExtensionUnpacker::Start)); 159c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 160c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 161c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid CrxInstaller::InstallUserScript(const FilePath& source_file, 162c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const GURL& original_url) { 163c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(!original_url.is_empty()); 164c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 165c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch source_file_ = source_file; 166c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch original_url_ = original_url; 167c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 168731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick BrowserThread::PostTask( 169731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick BrowserThread::FILE, FROM_HERE, 170c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NewRunnableMethod(this, &CrxInstaller::ConvertUserScriptOnFileThread)); 171c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 172c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 173c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid CrxInstaller::ConvertUserScriptOnFileThread() { 174c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::string error; 175513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch scoped_refptr<Extension> extension = 176513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch ConvertUserScriptToExtension(source_file_, original_url_, &error); 177c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!extension) { 178c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ReportFailureFromFileThread(error); 179c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 180c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 181c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 182c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch OnUnpackSuccess(extension->path(), extension->path(), extension); 183c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 184c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 185201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdochvoid CrxInstaller::InstallWebApp(const WebApplicationInfo& web_app) { 186201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch BrowserThread::PostTask( 187201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch BrowserThread::FILE, FROM_HERE, 188201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch NewRunnableMethod(this, &CrxInstaller::ConvertWebAppOnFileThread, 189201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch web_app)); 190201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch} 191201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch 192201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdochvoid CrxInstaller::ConvertWebAppOnFileThread( 193201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch const WebApplicationInfo& web_app) { 194201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch std::string error; 195201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch scoped_refptr<Extension> extension( 196201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch ConvertWebAppToExtension(web_app, base::Time::Now())); 197201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch if (!extension) { 198201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch // Validation should have stopped any potential errors before getting here. 199201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch NOTREACHED() << "Could not convert web app to extension."; 200201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch return; 201201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch } 202201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch 203201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch // TODO(aa): conversion data gets lost here :( 204201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch 205201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch OnUnpackSuccess(extension->path(), extension->path(), extension); 206201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch} 207201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch 208513209b27ff55e2841eac0e4120199c23acce758Ben Murdochbool CrxInstaller::AllowInstall(const Extension* extension, 209513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch std::string* error) { 210731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick DCHECK(error); 211731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick 212731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick // Make sure the expected id matches. 213731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick if (!expected_id_.empty() && expected_id_ != extension->id()) { 214731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick *error = base::StringPrintf( 215ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen "ID in new CRX manifest (%s) does not match expected id (%s)", 216731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick extension->id().c_str(), 217731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick expected_id_.c_str()); 218731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick return false; 219731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick } 220731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick 221ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (expected_version_.get() && 222ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen !expected_version_->Equals(*extension->version())) { 223ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen *error = base::StringPrintf( 224ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen "Version in new CRX %s manifest (%s) does not match expected " 225ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen "version (%s)", 226ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen extension->id().c_str(), 227ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen expected_version_->GetString().c_str(), 228ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen extension->version()->GetString().c_str()); 229ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return false; 230ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 231ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 232ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // The checks below are skipped for themes and external installs. 233ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (extension->is_theme() || Extension::IsExternalLocation(install_source_)) 234ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return true; 235ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 236ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (!extensions_enabled_) { 237ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen *error = "Extensions are not enabled."; 238ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return false; 239ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 240ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 241731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick if (extension_->is_app()) { 242731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick // If the app was downloaded, apps_require_extension_mime_type_ 243731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick // will be set. In this case, check that it was served with the 244731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick // right mime type. Make an exception for file URLs, which come 245731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick // from the users computer and have no headers. 246731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick if (!original_url_.SchemeIsFile() && 247731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick apps_require_extension_mime_type_ && 248731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick original_mime_type_ != Extension::kMimeType) { 249731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick *error = base::StringPrintf( 250731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick "Apps must be served with content type %s.", 251731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick Extension::kMimeType); 252731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick return false; 253731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick } 254731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick 255731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick // If the client_ is NULL, then the app is either being installed via 256731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick // an internal mechanism like sync, external_extensions, or default apps. 257731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick // In that case, we don't want to enforce things like the install origin. 258731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick if (!is_gallery_install_ && client_) { 259731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick // For apps with a gallery update URL, require that they be installed 260731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick // from the gallery. 261731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick // TODO(erikkay) Apply this rule for paid extensions and themes as well. 2624a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch if (extension->UpdatesFromGallery()) { 263731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick *error = l10n_util::GetStringFUTF8( 264731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick IDS_EXTENSION_DISALLOW_NON_DOWNLOADED_GALLERY_INSTALLS, 265731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick l10n_util::GetStringUTF16(IDS_EXTENSION_WEB_STORE_TITLE)); 266731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick return false; 267731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick } 268731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick 269731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick // For self-hosted apps, verify that the entire extent is on the same 270731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick // host (or a subdomain of the host) the download happened from. There's 271731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick // no way for us to verify that the app controls any other hosts. 272731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick URLPattern pattern(UserScript::kValidUserScriptSchemes); 273731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick pattern.set_host(original_url_.host()); 274731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick pattern.set_match_subdomains(true); 275731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick 276731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick ExtensionExtent::PatternList patterns = 277731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick extension_->web_extent().patterns(); 278731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick for (size_t i = 0; i < patterns.size(); ++i) { 279731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick if (!pattern.MatchesHost(patterns[i].host())) { 280731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick *error = base::StringPrintf( 281731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick "Apps must be served from the host that they affect."); 282731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick return false; 283731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick } 284731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick } 285731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick } 286731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick } 287731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick 288731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick return true; 289731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick} 290731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick 291c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid CrxInstaller::OnUnpackFailure(const std::string& error_message) { 292731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 293c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ReportFailureFromFileThread(error_message); 294c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 295c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 296c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid CrxInstaller::OnUnpackSuccess(const FilePath& temp_dir, 297c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const FilePath& extension_dir, 298513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch const Extension* extension) { 299731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 300c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 301c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Note: We take ownership of |extension| and |temp_dir|. 302513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch extension_ = extension; 303c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch temp_dir_ = temp_dir; 304c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 3053345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // We don't have to delete the unpack dir explicity since it is a child of 306c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // the temp dir. 307c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch unpacked_extension_root_ = extension_dir; 308c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 309731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick std::string error; 310731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick if (!AllowInstall(extension, &error)) { 311731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick ReportFailureFromFileThread(error); 312c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 313c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 314c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 315ac1e49eb6695f711d72215fcdf9388548942a00dBen Murdoch if (client_) { 316c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Extension::DecodeIcon(extension_.get(), Extension::EXTENSION_ICON_LARGE, 317c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch &install_icon_); 318c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 319c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 320731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick BrowserThread::PostTask( 321731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick BrowserThread::UI, FROM_HERE, 322c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NewRunnableMethod(this, &CrxInstaller::ConfirmInstall)); 323c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 324c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 325ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Helper method to let us compare a whitelisted manifest with the actual 326ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// downloaded extension's manifest, but ignoring the kPublicKey since the 327ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// whitelisted manifest doesn't have that value. 328ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenstatic bool EqualsIgnoringPublicKey( 329ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen const DictionaryValue& extension_manifest, 330ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen const DictionaryValue& whitelisted_manifest) { 331ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen scoped_ptr<DictionaryValue> manifest_copy(extension_manifest.DeepCopy()); 332ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen manifest_copy->Remove(extension_manifest_keys::kPublicKey, NULL); 333ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return manifest_copy->Equals(&whitelisted_manifest); 334ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen} 335ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 336c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid CrxInstaller::ConfirmInstall() { 337731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 338c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (frontend_->extension_prefs()->IsExtensionBlacklisted(extension_->id())) { 339513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch VLOG(1) << "This extension: " << extension_->id() 340513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch << " is blacklisted. Install failed."; 341c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ReportFailureFromUIThread("This extension is blacklisted."); 342c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 343c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 344c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 3453345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (!frontend_->extension_prefs()->IsExtensionAllowedByPolicy( 3463345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick extension_->id())) { 3473345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick ReportFailureFromUIThread("This extension is blacklisted by admin policy."); 3483345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick return; 3493345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick } 3503345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 351c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GURL overlapping_url; 352513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch const Extension* overlapping_extension = 353c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch frontend_->GetExtensionByOverlappingWebExtent(extension_->web_extent()); 35472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (overlapping_extension && 35572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen overlapping_extension->id() != extension_->id()) { 356c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ReportFailureFromUIThread(l10n_util::GetStringFUTF8( 357c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch IDS_EXTENSION_OVERLAPPING_WEB_EXTENT, 358c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch UTF8ToUTF16(overlapping_extension->name()))); 359c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 360c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 361c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 362c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch current_version_ = 363c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch frontend_->extension_prefs()->GetVersionString(extension_->id()); 364c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 365ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // First see if it's whitelisted by id (the old mechanism). 366513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch bool whitelisted = ClearWhitelistedInstallId(extension_->id()) && 3674a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch extension_->plugins().empty() && is_gallery_install_; 368513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch 369ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // Now check if it's whitelisted by manifest. 370ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen scoped_ptr<DictionaryValue> whitelisted_manifest( 371ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen RemoveWhitelistedManifest(extension_->id())); 372ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (is_gallery_install_ && whitelisted_manifest.get()) { 373ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (!EqualsIgnoringPublicKey(*extension_->manifest_value(), 374ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen *whitelisted_manifest)) { 375ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen ReportFailureFromUIThread( 376ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen l10n_util::GetStringUTF8(IDS_EXTENSION_MANIFEST_INVALID)); 377ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return; 378ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 379ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen whitelisted = true; 380ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 381ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 3823345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (client_ && 383513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch (!allow_silent_install_ || !whitelisted)) { 384c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch AddRef(); // Balanced in Proceed() and Abort(). 385c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch client_->ConfirmInstall(this, extension_.get()); 386c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 387731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick BrowserThread::PostTask( 388731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick BrowserThread::FILE, FROM_HERE, 389c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NewRunnableMethod(this, &CrxInstaller::CompleteInstall)); 390c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 391c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 392c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 393c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 3943345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid CrxInstaller::InstallUIProceed() { 395731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick BrowserThread::PostTask( 396731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick BrowserThread::FILE, FROM_HERE, 397c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NewRunnableMethod(this, &CrxInstaller::CompleteInstall)); 398c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 399c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Release(); // balanced in ConfirmInstall(). 400c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 401c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 402c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid CrxInstaller::InstallUIAbort() { 403ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // Technically, this can be called for other reasons than the user hitting 404ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // cancel, but they're rare. 405ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen ExtensionService::RecordPermissionMessagesHistogram( 406ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen extension_, "Extensions.Permissions_InstallCancel"); 407ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 408c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Kill the theme loading bubble. 409c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NotificationService* service = NotificationService::current(); 410c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch service->Notify(NotificationType::NO_THEME_DETECTED, 411c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Source<CrxInstaller>(this), 412c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NotificationService::NoDetails()); 413c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Release(); // balanced in ConfirmInstall(). 414c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 415c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // We're done. Since we don't post any more tasks to ourself, our ref count 416c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // should go to zero and we die. The destructor will clean up the temp dir. 417c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 418c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 419c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid CrxInstaller::CompleteInstall() { 420731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 421c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 422c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!current_version_.empty()) { 423c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch scoped_ptr<Version> current_version( 424c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Version::GetVersionFromString(current_version_)); 425c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (current_version->CompareTo(*(extension_->version())) > 0) { 426c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ReportFailureFromFileThread("Attempted to downgrade extension."); 427c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 428c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 429c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 430c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 431ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // See how long extension install paths are. This is important on 432ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // windows, because file operations may fail if the path to a file 433ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // exceeds a small constant. See crbug.com/69693 . 434ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen UMA_HISTOGRAM_CUSTOM_COUNTS( 435ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen "Extensions.CrxInstallDirPathLength", 436ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen install_directory_.value().length(), 0, 500, 100); 437ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 438c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FilePath version_dir = extension_file_util::InstallExtension( 439c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch unpacked_extension_root_, 440c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch extension_->id(), 441c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch extension_->VersionString(), 442c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch install_directory_); 443c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (version_dir.empty()) { 444c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ReportFailureFromFileThread( 445c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch l10n_util::GetStringUTF8( 446c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch IDS_EXTENSION_MOVE_DIRECTORY_TO_PROFILE_FAILED)); 447c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 448c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 449c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 450c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // This is lame, but we must reload the extension because absolute paths 451c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // inside the content scripts are established inside InitFromValue() and we 452c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // just moved the extension. 453c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // TODO(aa): All paths to resources inside extensions should be created 454c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // lazily and based on the Extension's root path at that moment. 455c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::string error; 456513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch extension_ = extension_file_util::LoadExtension( 457dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen version_dir, 458dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen install_source_, 459ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen Extension::REQUIRE_KEY, 460dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen &error); 461201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch CHECK(error.empty()) << error; 462c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 463c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ReportSuccessFromFileThread(); 464c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 465c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 466c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid CrxInstaller::ReportFailureFromFileThread(const std::string& error) { 467731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 468731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick BrowserThread::PostTask( 469731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick BrowserThread::UI, FROM_HERE, 470c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NewRunnableMethod(this, &CrxInstaller::ReportFailureFromUIThread, error)); 471c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 472c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 473c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid CrxInstaller::ReportFailureFromUIThread(const std::string& error) { 474731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 475c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 476c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NotificationService* service = NotificationService::current(); 477c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch service->Notify(NotificationType::EXTENSION_INSTALL_ERROR, 478c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Source<CrxInstaller>(this), 479c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Details<const std::string>(&error)); 480c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 481c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // This isn't really necessary, it is only used because unit tests expect to 482c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // see errors get reported via this interface. 483c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // 484c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // TODO(aa): Need to go through unit tests and clean them up too, probably get 485c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // rid of this line. 486c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ExtensionErrorReporter::GetInstance()->ReportError(error, false); // quiet 487c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 488c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (client_) 489c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch client_->OnInstallFailure(error); 490c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 491c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 492c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid CrxInstaller::ReportSuccessFromFileThread() { 493731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 494731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick BrowserThread::PostTask( 495731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick BrowserThread::UI, FROM_HERE, 496c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NewRunnableMethod(this, &CrxInstaller::ReportSuccessFromUIThread)); 497c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 498c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 499c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid CrxInstaller::ReportSuccessFromUIThread() { 500731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 501c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 502c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // If there is a client, tell the client about installation. 503c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (client_) 504ac1e49eb6695f711d72215fcdf9388548942a00dBen Murdoch client_->OnInstallSuccess(extension_.get(), install_icon_.get()); 505c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 506c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Tell the frontend about the installation and hand off ownership of 507c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // extension_ to it. 508201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch frontend_->OnExtensionInstalled(extension_); 509513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch extension_ = NULL; 510c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 511c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // We're done. We don't post any more tasks to ourselves so we are deleted 512c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // soon. 513c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 514