1 // Copyright 2018 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_FORCED_EXTENSIONS_INSTALL_STAGE_TRACKER_H_ 6 #define CHROME_BROWSER_EXTENSIONS_FORCED_EXTENSIONS_INSTALL_STAGE_TRACKER_H_ 7 8 #include <map> 9 #include <utility> 10 11 #include "base/observer_list.h" 12 #include "base/observer_list_types.h" 13 #include "base/optional.h" 14 #include "components/keyed_service/core/keyed_service.h" 15 #include "extensions/browser/install/crx_install_error.h" 16 #include "extensions/browser/install/sandboxed_unpacker_failure_reason.h" 17 #include "extensions/browser/install_stage.h" 18 #include "extensions/browser/updater/extension_downloader_delegate.h" 19 #include "extensions/browser/updater/safe_manifest_parser.h" 20 #include "extensions/common/extension_id.h" 21 22 #if defined(OS_CHROMEOS) 23 #include "components/user_manager/user_manager.h" 24 #endif // defined(OS_CHROMEOS) 25 26 class Profile; 27 28 namespace content { 29 class BrowserContext; 30 } // namespace content 31 32 namespace extensions { 33 34 // Tracker for extension installation events. Different parts of extension 35 // installation process report stage changes and failures to this one, where 36 // these events could be observed or retrieved later. 37 class InstallStageTracker : public KeyedService { 38 public: 39 // Stage of extension installing process. Typically forced extensions from 40 // policies should go through all stages in this order, other extensions skip 41 // CREATED stage. The stages are recorded in the increasing order of their 42 // values, therefore always verify that values are in increasing order and 43 // items are in order in which they appear. Exceptions are handled in 44 // ShouldOverrideCurrentStage method. Note: enum used for UMA. Do NOT reorder 45 // or remove entries. Don't forget to update enums.xml (name: 46 // ExtensionInstallationStage) when adding new entries. Don't forget to update 47 // device_management_backend.proto (name: 48 // ExtensionInstallReportLogEvent::InstallationStage) when adding new entries. 49 // Don't forget to update ConvertInstallationStageToProto method in 50 // ExtensionInstallEventLogCollector. 51 enum class Stage { 52 // Extension found in ForceInstall policy and added to 53 // ExtensionManagement::settings_by_id_. 54 CREATED = 0, 55 56 // NOTIFIED_FROM_MANAGEMENT = 5, // Moved to InstallCreationStage. 57 58 // NOTIFIED_FROM_MANAGEMENT_NOT_FORCED = 6, // Moved to 59 // InstallCreationStage. 60 61 // SEEN_BY_POLICY_LOADER = 7, // Moved to InstallCreationStage. 62 63 // SEEN_BY_EXTERNAL_PROVIDER = 8, // Moved to InstallCreationStage. 64 65 // Extension added to PendingExtensionManager. 66 PENDING = 1, 67 68 // Extension added to ExtensionDownloader. 69 DOWNLOADING = 2, 70 71 // Extension archive downloaded and is about to be unpacked/checked/etc. 72 INSTALLING = 3, 73 74 // Extension installation finished (either successfully or not). 75 COMPLETE = 4, 76 77 // Magic constant used by the histogram macros. 78 // Always update it to the max value. 79 kMaxValue = COMPLETE, 80 }; 81 82 // Intermediate stage of extension installation when the Stage is CREATED. 83 // TODO(crbug.com/989526): These stages are temporary ones for investigation. 84 // Remove them after investigation will complete. 85 // Note: enum used for UMA. Do NOT reorder or remove entries. Don't forget to 86 // update enums.xml (name: InstallCreationStage) when adding new 87 // entries. Don't forget to update device_management_backend.proto (name: 88 // ExtensionInstallReportLogEvent::InstallCreationStage) when adding new 89 // entries. Don't forget to update ConvertInstallCreationStageToProto method 90 // in ExtensionInstallEventLogCollector. 91 enum InstallCreationStage { 92 UNKNOWN = 0, 93 94 // ExtensionManagement has reported the Stage has Stage::CREATED. 95 CREATION_INITIATED = 1, 96 97 // Installation mode for the extension is set to INSTALLATION_FORCED just 98 // after ExtensionManagement class is created and CREATION_INITIATED has 99 // been reported. 100 NOTIFIED_FROM_MANAGEMENT_INITIAL_CREATION_FORCED = 2, 101 102 // Installation mode for the extension is set to other mode just after 103 // ExtensionManagement class is created and CREATION_INITIATED has been 104 // reported. 105 NOTIFIED_FROM_MANAGEMENT_INITIAL_CREATION_NOT_FORCED = 3, 106 107 // ExtensionManagement class is about to pass extension with 108 // INSTALLATION_FORCED mode to its observers. 109 NOTIFIED_FROM_MANAGEMENT = 4, 110 111 // ExtensionManagement class is about to pass extension with other mode to 112 // its observers. 113 NOTIFIED_FROM_MANAGEMENT_NOT_FORCED = 5, 114 115 // ExternalPolicyLoader with FORCED type fetches extension from 116 // ExtensionManagement. 117 SEEN_BY_POLICY_LOADER = 6, 118 119 // ExternalProviderImpl receives extension. 120 SEEN_BY_EXTERNAL_PROVIDER = 7, 121 122 // Magic constant used by the histogram macros. 123 // Always update it to the max value. 124 kMaxValue = SEEN_BY_EXTERNAL_PROVIDER, 125 }; 126 127 // Enum used for UMA. Do NOT reorder or remove entries. Don't forget to 128 // update enums.xml (name: ExtensionInstallationFailureReason) when adding new 129 // entries. Don't forget to update device_management_backend.proto (name: 130 // ExtensionInstallReportLogEvent::FailureReason) when adding new entries. 131 // Don't forget to update ConvertFailureReasonToProto method in 132 // ExtensionInstallEventLogCollector. 133 enum class FailureReason { 134 // Reason for the failure is not reported. Typically this should not happen, 135 // because if we know that we need to install an extension, it should 136 // immediately switch to CREATED stage leading to IN_PROGRESS failure 137 // reason, not UNKNOWN. 138 UNKNOWN = 0, 139 140 // Invalid id of the extension. 141 INVALID_ID = 1, 142 143 // Error during parsing extension individual settings. 144 MALFORMED_EXTENSION_SETTINGS = 2, 145 146 // The extension is marked as replaced by ARC app. 147 REPLACED_BY_ARC_APP = 3, 148 149 // Malformed extension dictionary for the extension. 150 MALFORMED_EXTENSION_DICT = 4, 151 152 // The extension format from extension dict is not supported. 153 NOT_SUPPORTED_EXTENSION_DICT = 5, 154 155 // Invalid file path in the extension dict. 156 MALFORMED_EXTENSION_DICT_FILE_PATH = 6, 157 158 // Invalid version in the extension dict. 159 MALFORMED_EXTENSION_DICT_VERSION = 7, 160 161 // Invalid updated URL in the extension dict. 162 MALFORMED_EXTENSION_DICT_UPDATE_URL = 8, 163 164 // The extension doesn't support browser locale. 165 LOCALE_NOT_SUPPORTED = 9, 166 167 // The extension marked as it shouldn't be installed. 168 NOT_PERFORMING_NEW_INSTALL = 10, 169 170 // Profile is older than supported by the extension. 171 TOO_OLD_PROFILE = 11, 172 173 // The extension can't be installed for enterprise. 174 DO_NOT_INSTALL_FOR_ENTERPRISE = 12, 175 176 // The extension is already installed. 177 ALREADY_INSTALLED = 13, 178 179 // The download of the crx failed. 180 CRX_FETCH_FAILED = 14, 181 182 // Failed to fetch the manifest for this extension. 183 MANIFEST_FETCH_FAILED = 15, 184 185 // The manifest couldn't be parsed. 186 MANIFEST_INVALID = 16, 187 188 // The manifest was fetched and parsed, and there are no updates for this 189 // extension. 190 NO_UPDATE = 17, 191 192 // The crx was downloaded, but failed to install. 193 // Corresponds to CrxInstallErrorType. 194 CRX_INSTALL_ERROR_DECLINED = 18, 195 CRX_INSTALL_ERROR_SANDBOXED_UNPACKER_FAILURE = 19, 196 CRX_INSTALL_ERROR_OTHER = 20, 197 198 // Extensions without update url should receive a default one, but somewhy 199 // this didn't work. Internal error, should never happen. 200 NO_UPDATE_URL = 21, 201 202 // Extension failed to add to PendingExtensionManager. 203 PENDING_ADD_FAILED = 22, 204 205 // ExtensionDownloader refuses to start downloading this extensions 206 // (possible reasons: invalid ID/URL). 207 DOWNLOADER_ADD_FAILED = 23, 208 209 // Extension (at the moment of check) is not installed nor some installation 210 // error reported, so extension is being installed now, stuck in some stage 211 // or some failure was not reported. See enum Stage for more details. 212 // This option is a failure only in the sense that we failed to install 213 // extension in required time. 214 IN_PROGRESS = 24, 215 216 // The download of the crx failed. In past histograms, this error has only 217 // occurred when the update check status is "no update" in the manifest. See 218 // crbug/1063031 for more details. 219 CRX_FETCH_URL_EMPTY = 25, 220 221 // The download of the crx failed. 222 CRX_FETCH_URL_INVALID = 26, 223 224 // Applying the ExtensionSettings policy changed installation mode from 225 // force-installed to anything else. 226 OVERRIDDEN_BY_SETTINGS = 27, 227 228 // Magic constant used by the histogram macros. 229 // Always update it to the max value. 230 kMaxValue = OVERRIDDEN_BY_SETTINGS, 231 }; 232 233 // Status for the app returned by server while fetching manifest when status 234 // was not OK. Enum used for UMA. Do NOT reorder or remove entries. Don't 235 // forget to update enums.xml (name: ManifestInvalidAppStatusError) when 236 // adding new entries. 237 enum class AppStatusError { 238 // Technically it may happen that update server return some unknown value or 239 // no value. 240 kUnknown = 0, 241 242 // The appid was not recognized and no action elements are included. 243 kErrorUnknownApplication = 1, 244 245 // The appid is not properly formed; no action elements are included. 246 kErrorInvalidAppId = 2, 247 248 // The application is not available to this user (usually based on country 249 // export restrictions). 250 kErrorRestricted = 3, 251 252 // Magic constant used by the histogram macros. 253 // Always update it to the max value. 254 kMaxValue = kErrorRestricted, 255 }; 256 257 // Info field in the update manifest returned by the server when no update is 258 // available. Enum used for UMA. Do NOT reorder or remove entries. Don't 259 // forget to update enums.xml (name: ExtensionNoUpdatesInfo) when adding new 260 // entries. 261 enum class NoUpdatesInfo { 262 // Update server returns some unknown value. 263 kUnknown = 0, 264 // Update server returns empty info. 265 kEmpty = 1, 266 // Popular no update reasons are marked as "rate limit", "disabled by 267 // client" and "bandwidth limit". 268 kRateLimit = 2, 269 kDisabledByClient = 3, 270 kBandwidthLimit = 4, 271 // Magic constant used by the histogram macros. 272 // Always update it to the max value. 273 kMaxValue = kBandwidthLimit, 274 }; 275 276 #if defined(OS_CHROMEOS) 277 // Contains information about the current user. 278 struct UserInfo { 279 UserInfo(const UserInfo&); 280 UserInfo(user_manager::UserType user_type, bool is_new_user); 281 282 user_manager::UserType user_type = user_manager::USER_TYPE_REGULAR; 283 bool is_new_user = false; 284 }; 285 #endif // defined(OS_CHROMEOS) 286 287 // Contains information about extension installation: failure reason, if any 288 // reported, specific details in case of CRX install error, current 289 // installation stage if known. 290 struct InstallationData { 291 InstallationData(); 292 InstallationData(const InstallationData&); 293 294 base::Optional<Stage> install_stage; 295 base::Optional<InstallCreationStage> install_creation_stage; 296 base::Optional<ExtensionDownloaderDelegate::Stage> downloading_stage; 297 base::Optional<ExtensionDownloaderDelegate::CacheStatus> 298 downloading_cache_status; 299 base::Optional<FailureReason> failure_reason; 300 base::Optional<CrxInstallErrorDetail> install_error_detail; 301 // Network error codes when failure_reason is CRX_FETCH_FAILED or 302 // MANIFEST_FETCH_FAILED. 303 base::Optional<int> network_error_code; 304 base::Optional<int> response_code; 305 // Number of fetch tries made when failure reason is CRX_FETCH_FAILED or 306 // MANIFEST_FETCH_FAILED. 307 base::Optional<int> fetch_tries; 308 // Unpack failure reason in case of 309 // CRX_INSTALL_ERROR_SANDBOXED_UNPACKER_FAILURE. 310 base::Optional<SandboxedUnpackerFailureReason> unpacker_failure_reason; 311 // Type of extension, assigned during CRX installation process. 312 base::Optional<Manifest::Type> extension_type; 313 // Error detail when the fetched manifest was invalid. This includes errors 314 // occurred while parsing the manifest and errors occurred due to the 315 // internal details of the parsed manifest. 316 base::Optional<ManifestInvalidError> manifest_invalid_error; 317 // Info field in the update manifest returned by the server when no update 318 // is available. 319 base::Optional<NoUpdatesInfo> no_updates_info; 320 // Type of app status error received from update server when manifest was 321 // fetched. 322 base::Optional<AppStatusError> app_status_error; 323 // Time at which the download is started. 324 base::Optional<base::TimeTicks> download_manifest_started_time; 325 // Time at which the update manifest is downloaded and successfully parsed 326 // from the server. 327 base::Optional<base::TimeTicks> download_manifest_finish_time; 328 // See InstallationStage enum. 329 base::Optional<InstallationStage> installation_stage; 330 // Time at which the download of CRX is started. 331 base::Optional<base::TimeTicks> download_CRX_started_time; 332 // Time at which CRX is downloaded. 333 base::Optional<base::TimeTicks> download_CRX_finish_time; 334 // Time at which signature verification of CRX is started. 335 base::Optional<base::TimeTicks> verification_started_time; 336 // Time at which copying of extension archive into the working directory is 337 // started. 338 base::Optional<base::TimeTicks> copying_started_time; 339 // Time at which unpacking of the extension archive is started. 340 base::Optional<base::TimeTicks> unpacking_started_time; 341 // Time at which the extension archive has been successfully unpacked and 342 // the expectation checks before extension installation are started. 343 base::Optional<base::TimeTicks> checking_expectations_started_time; 344 // Time at which the extension has passed the expectation checks and the 345 // installation is started. 346 base::Optional<base::TimeTicks> finalizing_started_time; 347 // Time at which the installation process is complete. 348 base::Optional<base::TimeTicks> installation_complete_time; 349 }; 350 351 class Observer : public base::CheckedObserver { 352 public: 353 ~Observer() override; 354 OnExtensionInstallationFailed(const ExtensionId & id,FailureReason reason)355 virtual void OnExtensionInstallationFailed(const ExtensionId& id, 356 FailureReason reason) {} 357 358 // Called when any change happens. For production please use more specific 359 // methods (create one if necessary). OnExtensionDataChangedForTesting(const ExtensionId & id,const content::BrowserContext * context,const InstallationData & data)360 virtual void OnExtensionDataChangedForTesting( 361 const ExtensionId& id, 362 const content::BrowserContext* context, 363 const InstallationData& data) {} 364 365 // Called when InstallStageTracker retrieves cache status for the 366 // extension. OnExtensionDownloadCacheStatusRetrieved(const ExtensionId & id,ExtensionDownloaderDelegate::CacheStatus cache_status)367 virtual void OnExtensionDownloadCacheStatusRetrieved( 368 const ExtensionId& id, 369 ExtensionDownloaderDelegate::CacheStatus cache_status) {} 370 371 // Called when installation stage of extension is updated. OnExtensionInstallationStageChanged(const ExtensionId & id,Stage stage)372 virtual void OnExtensionInstallationStageChanged(const ExtensionId& id, 373 Stage stage) {} 374 375 // Called when downloading stage of extension is updated. OnExtensionDownloadingStageChanged(const ExtensionId & id,ExtensionDownloaderDelegate::Stage stage)376 virtual void OnExtensionDownloadingStageChanged( 377 const ExtensionId& id, 378 ExtensionDownloaderDelegate::Stage stage) {} 379 380 // Called when InstallCreationStage of extension is updated. OnExtensionInstallCreationStageChanged(const ExtensionId & id,InstallCreationStage stage)381 virtual void OnExtensionInstallCreationStageChanged( 382 const ExtensionId& id, 383 InstallCreationStage stage) {} 384 }; 385 386 explicit InstallStageTracker(const content::BrowserContext* context); 387 388 ~InstallStageTracker() override; 389 390 InstallStageTracker(const InstallStageTracker&) = delete; 391 InstallStageTracker& operator=(const InstallStageTracker&) = delete; 392 393 // Convenience function to get the InstallStageTracker for a BrowserContext. 394 static InstallStageTracker* Get(content::BrowserContext* context); 395 396 #if defined(OS_CHROMEOS) 397 // Returns user type of the user associated with the |profile| and whether the 398 // user is new or not. This method should be used only if there is a user 399 // associated with the profile. 400 static UserInfo GetUserInfo(Profile* profile); 401 #endif // defined(OS_CHROMEOS) 402 403 void ReportInfoOnNoUpdatesFailure(const ExtensionId& id, 404 const std::string& info); 405 406 // Reports detailed error type when extension fails to install with failure 407 // reason MANIFEST_INVALID. See InstallationData::manifest_invalid_error 408 // for more details. 409 void ReportManifestInvalidFailure( 410 const ExtensionId& id, 411 const ExtensionDownloaderDelegate::FailureData& failure_data); 412 413 // Remembers failure reason and in-progress stages in memory. 414 void ReportInstallationStage(const ExtensionId& id, Stage stage); 415 void ReportInstallCreationStage(const ExtensionId& id, 416 InstallCreationStage stage); 417 void ReportFetchError( 418 const ExtensionId& id, 419 FailureReason reason, 420 const ExtensionDownloaderDelegate::FailureData& failure_data); 421 void ReportFailure(const ExtensionId& id, FailureReason reason); 422 void ReportDownloadingStage(const ExtensionId& id, 423 ExtensionDownloaderDelegate::Stage stage); 424 void ReportCRXInstallationStage(const ExtensionId& id, 425 InstallationStage stage); 426 void ReportDownloadingCacheStatus( 427 const ExtensionId& id, 428 ExtensionDownloaderDelegate::CacheStatus cache_status); 429 // Assigns the extension type. Reported from SandboxedInstalled when (and in 430 // case when) the extension type is discovered. 431 // See InstallationData::extension_type for more details. 432 void ReportExtensionType(const ExtensionId& id, 433 Manifest::Type extension_type); 434 void ReportCrxInstallError(const ExtensionId& id, 435 FailureReason reason, 436 CrxInstallErrorDetail crx_install_error); 437 void ReportSandboxedUnpackerFailureReason( 438 const ExtensionId& id, 439 SandboxedUnpackerFailureReason unpacker_failure_reason); 440 441 // Retrieves known information for installation of extension |id|. 442 // Returns empty data if not found. 443 InstallationData Get(const ExtensionId& id); 444 static std::string GetFormattedInstallationData(const InstallationData& data); 445 446 // Clears all collected failures and stages. 447 void Clear(); 448 449 void AddObserver(Observer* observer); 450 void RemoveObserver(Observer* observer); 451 452 private: 453 // Helper function that maps the current app status to AppStatusError enum. 454 AppStatusError GetManifestInvalidAppStatusError(const std::string& status); 455 456 // Helper function to report installation failures to the observers. 457 void NotifyObserversOfFailure(const ExtensionId& id, 458 FailureReason reason, 459 const InstallationData& data); 460 461 const content::BrowserContext* browser_context_; 462 463 std::map<ExtensionId, InstallationData> installation_data_map_; 464 465 base::ObserverList<Observer> observers_; 466 }; 467 468 } // namespace extensions 469 470 #endif // CHROME_BROWSER_EXTENSIONS_FORCED_EXTENSIONS_INSTALL_STAGE_TRACKER_H_ 471