1// Copyright (c) 2012 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#ifndef CHROME_BROWSER_EXTENSIONS_CRX_INSTALLER_H_ 6#define CHROME_BROWSER_EXTENSIONS_CRX_INSTALLER_H_ 7 8#include <string> 9 10#include "base/compiler_specific.h" 11#include "base/files/file_path.h" 12#include "base/memory/ref_counted.h" 13#include "base/memory/weak_ptr.h" 14#include "base/version.h" 15#include "chrome/browser/extensions/blacklist.h" 16#include "chrome/browser/extensions/extension_install_prompt.h" 17#include "chrome/browser/extensions/extension_installer.h" 18#include "chrome/browser/extensions/sandboxed_unpacker.h" 19#include "chrome/browser/extensions/webstore_installer.h" 20#include "chrome/common/extensions/extension.h" 21#include "chrome/common/extensions/manifest.h" 22#include "sync/api/string_ordinal.h" 23 24class ExtensionService; 25class ExtensionServiceTest; 26class SkBitmap; 27struct WebApplicationInfo; 28 29namespace base { 30class SequencedTaskRunner; 31} 32 33namespace extensions { 34class CrxInstallerError; 35class ExtensionUpdaterTest; 36class RequirementsChecker; 37 38// This class installs a crx file into a profile. 39// 40// Installing a CRX is a multi-step process, including unpacking the crx, 41// validating it, prompting the user, and installing. Since many of these 42// steps must occur on the file thread, this class contains a copy of all data 43// necessary to do its job. (This also minimizes external dependencies for 44// easier testing). 45// 46// Lifetime management: 47// 48// This class is ref-counted by each call it makes to itself on another thread, 49// and by UtilityProcessHost. 50// 51// Additionally, we hold a reference to our own client so that it lives at least 52// long enough to receive the result of unpacking. 53// 54// IMPORTANT: Callers should keep a reference to a CrxInstaller while they are 55// working with it, eg: 56// 57// scoped_refptr<CrxInstaller> installer(new CrxInstaller(...)); 58// installer->set_foo(); 59// installer->set_bar(); 60// installer->InstallCrx(...); 61// 62// Installation is aborted if the extension service learns that Chrome is 63// terminating during the install. We can't listen for the app termination 64// notification here in this class because it can be destroyed on any thread 65// and won't safely be able to clean up UI thread notification listeners. 66class CrxInstaller 67 : public SandboxedUnpackerClient, 68 public ExtensionInstallPrompt::Delegate { 69 public: 70 // Used in histograms; do not change order. 71 enum OffStoreInstallAllowReason { 72 OffStoreInstallDisallowed, 73 OffStoreInstallAllowedFromSettingsPage, 74 OffStoreInstallAllowedBecausePref, 75 OffStoreInstallAllowedInTest, 76 NumOffStoreInstallAllowReasons 77 }; 78 79 // Extensions will be installed into service->install_directory(), then 80 // registered with |service|. This does a silent install - see below for 81 // other options. 82 static scoped_refptr<CrxInstaller> CreateSilent(ExtensionService* service); 83 84 // Same as above, but use |client| to generate a confirmation prompt. 85 static scoped_refptr<CrxInstaller> Create( 86 ExtensionService* service, 87 scoped_ptr<ExtensionInstallPrompt> client); 88 89 // Same as the previous method, except use the |approval| to bypass the 90 // prompt. Note that the caller retains ownership of |approval|. 91 static scoped_refptr<CrxInstaller> Create( 92 ExtensionService* service, 93 scoped_ptr<ExtensionInstallPrompt> client, 94 const WebstoreInstaller::Approval* approval); 95 96 // Install the crx in |source_file|. 97 void InstallCrx(const base::FilePath& source_file); 98 99 // Convert the specified user script into an extension and install it. 100 void InstallUserScript(const base::FilePath& source_file, 101 const GURL& download_url); 102 103 // Convert the specified web app into an extension and install it. 104 void InstallWebApp(const WebApplicationInfo& web_app); 105 106 // Overridden from ExtensionInstallPrompt::Delegate: 107 virtual void InstallUIProceed() OVERRIDE; 108 virtual void InstallUIAbort(bool user_initiated) OVERRIDE; 109 110 int creation_flags() const { return creation_flags_; } 111 void set_creation_flags(int val) { creation_flags_ = val; } 112 113 const GURL& download_url() const { return download_url_; } 114 void set_download_url(const GURL& val) { download_url_ = val; } 115 116 const base::FilePath& source_file() const { return source_file_; } 117 118 Manifest::Location install_source() const { 119 return install_source_; 120 } 121 void set_install_source(Manifest::Location source) { 122 install_source_ = source; 123 } 124 125 const std::string& expected_id() const { return expected_id_; } 126 void set_expected_id(const std::string& val) { expected_id_ = val; } 127 128 void set_expected_version(const Version& val) { 129 expected_version_.reset(new Version(val)); 130 } 131 132 bool delete_source() const { return delete_source_; } 133 void set_delete_source(bool val) { delete_source_ = val; } 134 135 bool allow_silent_install() const { return allow_silent_install_; } 136 void set_allow_silent_install(bool val) { allow_silent_install_ = val; } 137 138 bool is_gallery_install() const { 139 return (creation_flags_ & Extension::FROM_WEBSTORE) > 0; 140 } 141 void set_is_gallery_install(bool val) { 142 if (val) 143 creation_flags_ |= Extension::FROM_WEBSTORE; 144 else 145 creation_flags_ &= ~Extension::FROM_WEBSTORE; 146 } 147 148 // The original download URL should be set when the WebstoreInstaller is 149 // tracking the installation. The WebstoreInstaller uses this URL to match 150 // failure notifications to the extension. 151 const GURL& original_download_url() const { return original_download_url_; } 152 void set_original_download_url(const GURL& url) { 153 original_download_url_ = url; 154 } 155 156 // If |apps_require_extension_mime_type_| is set to true, be sure to set 157 // |original_mime_type_| as well. 158 void set_apps_require_extension_mime_type( 159 bool apps_require_extension_mime_type) { 160 apps_require_extension_mime_type_ = apps_require_extension_mime_type; 161 } 162 163 void set_original_mime_type(const std::string& original_mime_type) { 164 original_mime_type_ = original_mime_type; 165 } 166 167 extension_misc::CrxInstallCause install_cause() const { 168 return install_cause_; 169 } 170 void set_install_cause(extension_misc::CrxInstallCause install_cause) { 171 install_cause_ = install_cause; 172 } 173 174 OffStoreInstallAllowReason off_store_install_allow_reason() const { 175 return off_store_install_allow_reason_; 176 } 177 void set_off_store_install_allow_reason(OffStoreInstallAllowReason reason) { 178 off_store_install_allow_reason_ = reason; 179 } 180 181 void set_page_ordinal(const syncer::StringOrdinal& page_ordinal) { 182 page_ordinal_ = page_ordinal; 183 } 184 185 void set_error_on_unsupported_requirements(bool val) { 186 error_on_unsupported_requirements_ = val; 187 } 188 189 void set_install_wait_for_idle(bool val) { 190 install_wait_for_idle_ = val; 191 } 192 193 bool did_handle_successfully() const { return did_handle_successfully_; } 194 195 Profile* profile() { return installer_.profile(); } 196 197 const Extension* extension() { return installer_.extension().get(); } 198 199 private: 200 friend class ::ExtensionServiceTest; 201 friend class ExtensionUpdaterTest; 202 friend class ExtensionCrxInstallerTest; 203 204 CrxInstaller(base::WeakPtr<ExtensionService> service_weak, 205 scoped_ptr<ExtensionInstallPrompt> client, 206 const WebstoreInstaller::Approval* approval); 207 virtual ~CrxInstaller(); 208 209 // Converts the source user script to an extension. 210 void ConvertUserScriptOnFileThread(); 211 212 // Converts the source web app to an extension. 213 void ConvertWebAppOnFileThread(const WebApplicationInfo& web_app, 214 const base::FilePath& install_directory); 215 216 // Called after OnUnpackSuccess as a last check to see whether the install 217 // should complete. 218 CrxInstallerError AllowInstall(const Extension* extension); 219 220 // SandboxedUnpackerClient 221 virtual void OnUnpackFailure(const string16& error_message) OVERRIDE; 222 virtual void OnUnpackSuccess(const base::FilePath& temp_dir, 223 const base::FilePath& extension_dir, 224 const base::DictionaryValue* original_manifest, 225 const Extension* extension, 226 const SkBitmap& install_icon) OVERRIDE; 227 228 // Called on the UI thread to start the requirements check on the extension. 229 void CheckImportsAndRequirements(); 230 231 // Runs on the UI thread. Callback from RequirementsChecker. 232 void OnRequirementsChecked(std::vector<std::string> requirement_errors); 233 234 // Runs on the UI thread. Callback from Blacklist. 235 void OnBlacklistChecked( 236 extensions::Blacklist::BlacklistState blacklist_state); 237 238 // Runs on the UI thread. Confirms the installation to the ExtensionService. 239 void ConfirmInstall(); 240 241 // Runs on File thread. Install the unpacked extension into the profile and 242 // notify the frontend. 243 void CompleteInstall(); 244 245 // Result reporting. 246 void ReportFailureFromFileThread(const CrxInstallerError& error); 247 void ReportFailureFromUIThread(const CrxInstallerError& error); 248 void ReportSuccessFromFileThread(); 249 void ReportSuccessFromUIThread(); 250 void NotifyCrxInstallComplete(bool success); 251 252 // Deletes temporary directory and crx file if needed. 253 void CleanupTempFiles(); 254 255 // Checks whether the current installation is initiated by the user from 256 // the extension settings page to update an existing extension or app. 257 void CheckUpdateFromSettingsPage(); 258 259 // Show re-enable prompt if the update is initiated from the settings page 260 // and needs additional permissions. 261 void ConfirmReEnable(); 262 263 // The file we're installing. 264 base::FilePath source_file_; 265 266 // The URL the file was downloaded from. 267 GURL download_url_; 268 269 // The directory extensions are installed to. 270 base::FilePath install_directory_; 271 272 // The location the installation came from (bundled with Chromium, registry, 273 // manual install, etc). This metadata is saved with the installation if 274 // successful. Defaults to INTERNAL. 275 Manifest::Location install_source_; 276 277 // Indicates whether the user has already approved the extension to be 278 // installed. If true, |expected_manifest_| and |expected_id_| must match 279 // those of the CRX. 280 bool approved_; 281 282 // For updates, external and webstore installs we have an ID we're expecting 283 // the extension to contain. 284 std::string expected_id_; 285 286 // A parsed copy of the expected manifest, before any transformations like 287 // localization have taken place. If |approved_| is true, then the 288 // extension's manifest must match this for the install to proceed. 289 scoped_ptr<Manifest> expected_manifest_; 290 291 // If non-NULL, contains the expected version of the extension we're 292 // installing. Important for external sources, where claiming the wrong 293 // version could cause unnecessary unpacking of an extension at every 294 // restart. 295 scoped_ptr<Version> expected_version_; 296 297 // Whether manual extension installation is enabled. We can't just check this 298 // before trying to install because themes are special-cased to always be 299 // allowed. 300 bool extensions_enabled_; 301 302 // Whether we're supposed to delete the source file on destruction. Defaults 303 // to false. 304 bool delete_source_; 305 306 // The download URL, before redirects, if this is a gallery install. 307 GURL original_download_url_; 308 309 // Whether to create an app shortcut after successful installation. This is 310 // set based on the user's selection in the UI and can only ever be true for 311 // apps. 312 bool create_app_shortcut_; 313 314 // The ordinal of the NTP apps page |extension_| will be shown on. 315 syncer::StringOrdinal page_ordinal_; 316 317 // A parsed copy of the unmodified original manifest, before any 318 // transformations like localization have taken place. 319 scoped_ptr<Manifest> original_manifest_; 320 321 // If non-empty, contains the current version of the extension we're 322 // installing (for upgrades). 323 std::string current_version_; 324 325 // The icon we will display in the installation UI, if any. 326 scoped_ptr<SkBitmap> install_icon_; 327 328 // The temp directory extension resources were unpacked to. We own this and 329 // must delete it when we are done with it. 330 base::FilePath temp_dir_; 331 332 // The frontend we will report results back to. 333 base::WeakPtr<ExtensionService> service_weak_; 334 335 // The client we will work with to do the installation. This can be NULL, in 336 // which case the install is silent. 337 // NOTE: we may be deleted on the file thread. To ensure the UI is deleted on 338 // the main thread we don't use a scoped_ptr here. 339 ExtensionInstallPrompt* client_; 340 341 // The root of the unpacked extension directory. This is a subdirectory of 342 // temp_dir_, so we don't have to delete it explicitly. 343 base::FilePath unpacked_extension_root_; 344 345 // True when the CRX being installed was just downloaded. 346 // Used to trigger extra checks before installing. 347 bool apps_require_extension_mime_type_; 348 349 // Allows for the possibility of a normal install (one in which a |client| 350 // is provided in the ctor) to procede without showing the permissions prompt 351 // dialog. 352 bool allow_silent_install_; 353 354 // The value of the content type header sent with the CRX. 355 // Ignorred unless |require_extension_mime_type_| is true. 356 std::string original_mime_type_; 357 358 // What caused this install? Used only for histograms that report 359 // on failure rates, broken down by the cause of the install. 360 extension_misc::CrxInstallCause install_cause_; 361 362 // Creation flags to use for the extension. These flags will be used 363 // when calling Extenion::Create() by the crx installer. 364 int creation_flags_; 365 366 // Whether to allow off store installation. 367 OffStoreInstallAllowReason off_store_install_allow_reason_; 368 369 // Whether the installation was handled successfully. This is used to 370 // indicate to the client whether the file should be removed and any UI 371 // initiating the installation can be removed. This is different than whether 372 // there was an error; if there was an error that rejects installation we 373 // still consider the installation 'handled'. 374 bool did_handle_successfully_; 375 376 // Whether we should produce an error if the manifest declares requirements 377 // that are not met. If false and there is an unmet requirement, the install 378 // will continue but the extension will be distabled. 379 bool error_on_unsupported_requirements_; 380 381 bool has_requirement_errors_; 382 383 extensions::Blacklist::BlacklistState blacklist_state_; 384 385 bool install_wait_for_idle_; 386 387 // Sequenced task runner where file I/O operations will be performed. 388 scoped_refptr<base::SequencedTaskRunner> installer_task_runner_; 389 390 // Used to show the install dialog. 391 ExtensionInstallPrompt::ShowDialogCallback show_dialog_callback_; 392 393 // Whether the update is initiated by the user from the extension settings 394 // page. 395 bool update_from_settings_page_; 396 397 // Gives access to common methods and data of an extension installer. 398 ExtensionInstaller installer_; 399 400 DISALLOW_COPY_AND_ASSIGN(CrxInstaller); 401}; 402 403} // namespace extensions 404 405#endif // CHROME_BROWSER_EXTENSIONS_CRX_INSTALLER_H_ 406