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