File: extension_telemetry_service.h

package info (click to toggle)
chromium 139.0.7258.127-1
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 6,122,068 kB
  • sloc: cpp: 35,100,771; ansic: 7,163,530; javascript: 4,103,002; python: 1,436,920; asm: 946,517; xml: 746,709; pascal: 187,653; perl: 88,691; sh: 88,436; objc: 79,953; sql: 51,488; cs: 44,583; fortran: 24,137; makefile: 22,147; tcl: 15,277; php: 13,980; yacc: 8,984; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (412 lines) | stat: -rw-r--r-- 17,405 bytes parent folder | download | duplicates (6)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CHROME_BROWSER_SAFE_BROWSING_EXTENSION_TELEMETRY_EXTENSION_TELEMETRY_SERVICE_H_
#define CHROME_BROWSER_SAFE_BROWSING_EXTENSION_TELEMETRY_EXTENSION_TELEMETRY_SERVICE_H_

#include <memory>

#include "base/containers/flat_map.h"
#include "base/containers/flat_set.h"
#include "base/files/file_path.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/threading/sequence_bound.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
#include "base/values.h"
#include "components/keyed_service/core/keyed_service.h"
#include "components/prefs/pref_change_registrar.h"
#include "extensions/common/extension_id.h"
#include "extensions/common/extension_set.h"

class Profile;
class PrefService;

namespace extensions {
class Extension;
class ExtensionPrefs;
class ExtensionRegistry;
}  // namespace extensions

namespace network {
class SharedURLLoaderFactory;
}  // namespace network

namespace safe_browsing {

enum class ExtensionSignalType;
class ExtensionSignal;
class ExtensionSignalProcessor;
class ExtensionTelemetryConfigManager;
class ExtensionTelemetryFileProcessor;
class ExtensionTelemetryPersister;
class ExtensionTelemetryReportRequest;
class ExtensionTelemetryReportRequest_ExtensionInfo;
class ExtensionTelemetryReportRequest_ExtensionInfo_FileInfo;
class ExtensionTelemetryReportResponse;
class ExtensionTelemetryUploader;
class SafeBrowsingTokenFetcher;

// This class processes extension signals and reports telemetry for a given
// profile (regular profile only). It is used exclusively on the UI thread.
// Lifetime:
// The service is instantiated when the associated profile is instantiated. It
// is destructed when the corresponding profile is destructed.
// Enable/Disable states:
// The service is enabled if:
//  - the user is opted into Enhanced Safe Browsing (ESB) OR
//  - enterprise telemetry is enabled by a policy
//
// |esb_enabled_| - Generates telemetry reports for Enhanced Safe Browsing
// (ESB) users. When enabled, the service receives/stores signal
// information, and collects file data for off-store extensions.
// Periodically, the telemetry reports are uploaded to the SB servers. In
// the upload response, the CRX telemetry server includes unsafe off-store
// extension verdicts that the service can take action on.
// |enterprise_enabled_| - Generates enterprise telemetry reports for
// managed profiles. When enabled, the service also collects signal
// information and file data for off-store extensions. Periodically, the
// telemetry reports are sent to the Chrome Enterprise Reporting servers
// instead. Unlike the ESB flow, there is no response received when an
// enterprise report is sent.
//
// For both ESB and enterprise: when disabled, any previously stored signal
// information is cleared, incoming signals are ignored and no reports are
// sent.
class ExtensionTelemetryService : public KeyedService {
 public:
  // Convenience method to get the service for a profile.
  static ExtensionTelemetryService* Get(Profile* profile);

  ExtensionTelemetryService(ExtensionTelemetryService&&) = delete;
  ExtensionTelemetryService& operator=(ExtensionTelemetryService&&) = delete;
  ExtensionTelemetryService(
      Profile* profile,
      scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory);

  ExtensionTelemetryService(const ExtensionTelemetryService&) = delete;
  ExtensionTelemetryService& operator=(const ExtensionTelemetryService&) =
      delete;

  ~ExtensionTelemetryService() override;

  // Records the signal type when a signal is:
  // - created externally and passed to extension service using AddSignal OR
  // - created internally by a signal processor from other signals received.
  static void RecordSignalType(ExtensionSignalType signal_type);

  // Recorded when a signal is discarded because it contains invalid data (e.g.,
  // invalid extension id).
  static void RecordSignalDiscarded(ExtensionSignalType signal_type);

  // Enables/disables the service for ESB reports.
  void SetEnabledForESB(bool enable);
  // Enables/disables the service for Enterprise reports.
  void SetEnabledForEnterprise(bool enable);
  // Returns true if the telemetry service is enabled for either ESB,
  // enterprise, or both.
  bool enabled() const;

  // Accepts extension telemetry signals for processing.
  void AddSignal(std::unique_ptr<ExtensionSignal> signal);

  // Checks the `extension_id` and `signal_type` against the
  // configuration and reports true if the signal should be created.
  bool IsSignalEnabled(const extensions::ExtensionId& extension_id,
                       ExtensionSignalType signal_type) const;

  base::TimeDelta current_reporting_interval() {
    return current_reporting_interval_;
  }

  // KeyedService:
  void Shutdown() override;

  base::TimeDelta GetOffstoreFileDataCollectionStartupDelaySeconds();
  base::TimeDelta GetOffstoreFileDataCollectionIntervalSeconds();

 private:
  using SignalProcessors =
      base::flat_map<ExtensionSignalType,
                     std::unique_ptr<ExtensionSignalProcessor>>;
  using SignalSubscribers = base::flat_map<
      ExtensionSignalType,
      std::vector<raw_ptr<ExtensionSignalProcessor, VectorExperimental>>>;
  // Maps extension id to extension data.
  using ExtensionStore = base::flat_map<
      extensions::ExtensionId,
      std::unique_ptr<ExtensionTelemetryReportRequest_ExtensionInfo>>;

  // Called when the pref that affects ESB telemetry reporting is changed.
  void OnESBPrefChanged();

  // Called when the policy that affects enterprise telemetry reporting is
  // changed.
  void OnEnterprisePolicyChanged();

  // Helper method to add and process an extension signal. Shared by both ESB
  // and enterprise reporting.
  void AddSignalHelper(const ExtensionSignal& signal,
                       ExtensionStore& store,
                       SignalSubscribers& subscribers);

  // Creates a telemetry report with common fields shared by both ESB and
  // enterprise reporting.
  std::unique_ptr<ExtensionTelemetryReportRequest>
  CreateReportWithCommonFieldsPopulated();

  // Creates and uploads telemetry reports.
  void CreateAndUploadReport();

  // Creates and sends telemetry report to enterprise.
  void CreateAndSendEnterpriseReport();

  void OnUploadComplete(bool success, const std::string& response_data);

  // Returns a bool that represents if there is any signal processor
  // information to report.
  bool SignalDataPresent() const;

  // Creates telemetry report protobuf for all extension store extensions
  // and currently installed extensions along with signal data retrieved from
  // signal processors.
  std::unique_ptr<ExtensionTelemetryReportRequest> CreateReport();
  // For enterprise, a report is only created for extensions with signals data.
  std::unique_ptr<ExtensionTelemetryReportRequest> CreateReportForEnterprise();

  // Dumps a telemetry report in logs for testing.
  void DumpReportForTesting(const ExtensionTelemetryReportRequest& report);

  // Collects extension information for reporting.
  std::unique_ptr<ExtensionTelemetryReportRequest_ExtensionInfo>
  GetExtensionInfoForReport(const extensions::Extension& extension);

  void UploadPersistedFile(std::string report);

  // Creates access token fetcher based on profile log-in status.
  // Returns nullptr when the user is not signed in.
  std::unique_ptr<SafeBrowsingTokenFetcher> GetTokenFetcher();

  // Called periodically based on the Telemetry Service timer. If time
  // elapsed since last upload is less than the reporting interval, persists
  // a new report, else uploads current report and any persisted reports.
  void PersistOrUploadData();

  // Uploads an extension telemetry report.
  void UploadReport(std::unique_ptr<std::string> report);

  // Checks the time of the last upload and if enough time has passed,
  // uploads telemetry data. Runs on a delayed post task on startup.
  void StartUploadCheck();

  // Callback used to receive information about any extensions present in
  // the Chrome command line switch, --load-extension. The information is
  // collected off the UI thread since it involves reading the manifest file of
  // the extension. The callback stores the received information, a set of
  // extension objects, in `commandline_extensions_`.
  // NOTE: The extension objects are created without actually installing the
  // extensions.
  void OnCommandLineExtensionsInfoCollected(
      extensions::ExtensionSet commandline_extensions);

  // Sets up signal processors and subscribers for ESB telemetry.
  void SetUpSignalProcessorsAndSubscribersForESB();

  // Sets up signal processors and subscribers for enterprise telemetry.
  void SetUpSignalProcessorsAndSubscribersForEnterprise();

  // Sets up the off-store file data collection: file processor, timer, and
  // command line extensions. If it is already set up, this is a no-op.
  void SetUpOffstoreFileDataCollection();

  // Searches for offstore extensions, collects file data such as
  // hashes/manifest content, and saves the data to PrefService. Repeats every 2
  // hours. This method is repeated periodically (default 2 hours) to check if
  // the file data needs to be updated. File data is updated once every 24 hours
  // by default.
  void StartOffstoreFileDataCollection();

  // Searches through the extension registry for offstore extensions and
  // populates |offstore_extension_dirs_| with extension id and root directory.
  // An off-store extension is defined as not from the webstore and not
  // installed from components.
  void GetOffstoreExtensionDirs();

  // Remove any stale off-store file data stored in prefs. The data is
  // considered stale if the associated off-store extension is no longer
  // installed or no longer part of the --load-extension command line switch.
  void RemoveStaleExtensionsFileDataFromPref();

  // Collect file data from an offstore extension by making a call to the
  // FileProcessor.
  void CollectOffstoreFileData();

  // Stores information to identify file data collected for each offstore
  // extension.
  struct OffstoreExtensionFileDataContext {
    OffstoreExtensionFileDataContext(
        const extensions::ExtensionId& extension_id,
        const base::FilePath& root_dir);
    OffstoreExtensionFileDataContext(
        const extensions::ExtensionId& extension_id,
        const base::FilePath& root_dir,
        const base::Time& last_processed_time);

    extensions::ExtensionId extension_id;
    base::FilePath root_dir;
    base::Time last_processed_time;

    bool operator<(const OffstoreExtensionFileDataContext& other) const;
  };

  // Callback invoked when file data for an extension is completed. The data is
  // saved to Prefs and the next extension file data collection is initiated.
  void OnOffstoreFileDataCollected(
      base::flat_set<OffstoreExtensionFileDataContext>::iterator context,
      base::Value::Dict file_data);

  // Stops and clears any offstore file data collection objects/contexts.
  void StopOffstoreFileDataCollection();

  // Stores offstore extension file data retrieved from PrefService.
  struct OffstoreExtensionFileData {
    OffstoreExtensionFileData();
    ~OffstoreExtensionFileData();
    OffstoreExtensionFileData(const OffstoreExtensionFileData&);

    std::string manifest;
    std::vector<ExtensionTelemetryReportRequest_ExtensionInfo_FileInfo>
        file_infos;
  };

  // Given an |extension_id|, retrieves the collected file data from PrefService
  // if available.
  std::optional<OffstoreExtensionFileData> RetrieveOffstoreFileDataForReport(
      const extensions::ExtensionId& extension_id);

  // Validates offending off-store extension verdicts received in a telemetry
  // report response, and converts them into a blocklist state map for the
  // ExtensionService to act on.
  void ProcessOffstoreExtensionVerdicts(
      const ExtensionTelemetryReportResponse& response);

  // Common variables shared between ESB and enterprise reporting:
  // The profile with which this instance of the service is associated.
  const raw_ptr<Profile> profile_;

  // Unowned objects used for getting extension information.
  const raw_ptr<extensions::ExtensionRegistry> extension_registry_;
  const raw_ptr<extensions::ExtensionPrefs> extension_prefs_;

  // The |file_processor_| object reads and hashes offstore extension files.
  // Since these are blocking operations, it is bound to a different sequence
  // task runner.
  base::SequenceBound<ExtensionTelemetryFileProcessor> file_processor_;

  // Stores extension objects for extensions that are included in the
  // --load-extension command line switch.
  extensions::ExtensionSet commandline_extensions_;
  // Used to ensure that the information about command line extensions is only
  // collected once.
  bool collected_commandline_extension_info_ = false;

  // Maps offstore extension id to extension root path
  using OffstoreExtensionDirs =
      base::flat_map<extensions::ExtensionId, base::FilePath>;
  OffstoreExtensionDirs offstore_extension_dirs_;
  // Set of offstore extensions to process in order. Sorted by oldest last
  // processing time.
  base::flat_set<OffstoreExtensionFileDataContext>
      offstore_extension_file_data_contexts_;
  // Used to start the initial offstore extension file data collection based on
  // |kOffstoreFileDataCollectionStartupDelaySeconds| - default: 5 mins.
  // Then repeat the collection based on
  // |kOffstoreFileDataCollectionIntervalSeconds| - default: 2 hours.
  base::OneShotTimer offstore_file_data_collection_timer_;
  base::TimeTicks offstore_file_data_collection_start_time_;
  base::TimeDelta offstore_file_data_collection_duration_limit_;

  // ESB-specific reporting variables:
  // Keeps track of the state of the service for ESB telemetry reporting.
  bool esb_enabled_ = false;

  SignalProcessors signal_processors_;
  SignalSubscribers signal_subscribers_;

  // Stores data on extensions with generated signals for ESB reporting.
  ExtensionStore extension_store_;

  // Used for periodic collection of ESB telemetry reports.
  base::RepeatingTimer timer_;
  base::TimeDelta current_reporting_interval_;

  // The persister object is bound to the threadpool. This prevents the
  // the read/write operations the `persister_` runs from blocking
  // the UI thread. It also allows the `persister_` object to be
  // destroyed cleanly while running tasks during Chrome shutdown.
  base::SequenceBound<ExtensionTelemetryPersister> persister_;

  // The `config_manager_` manages all configurable variables of the
  // Extension Telemetry Service. Variables are stored in Chrome Prefs
  // between sessions.
  std::unique_ptr<safe_browsing::ExtensionTelemetryConfigManager>
      config_manager_;

  // The URLLoaderFactory used to issue network requests.
  scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_;

  // Unowned object used for getting preference settings.
  raw_ptr<PrefService> pref_service_;

  // Observes changes to kSafeBrowsingEnhanced.
  PrefChangeRegistrar pref_change_registrar_;

  // Specifies the number of times(N) the telemetry service checks if a
  // telemetry upload is required within an upload interval(I). The telemetry
  // service checks if an upload is necessary at I/N intervals. At each check
  // interval, the in-memory telemetry data is saved to disk - till the time an
  // upload interval has elapsed. For example, a value of 2 means that the
  // telemetry service checks for uploads at I/2 and I. At the first check
  // interval, the in-memory report is written to disk. At the second check
  // interval, the in-memory report and the previously saved report in disk are
  // both uploaded to the telemetry server.
  int num_checks_per_upload_interval_;

  // The current report being uploaded.
  std::unique_ptr<ExtensionTelemetryReportRequest> active_report_;
  // The current uploader instance uploading the active report.
  std::unique_ptr<ExtensionTelemetryUploader> active_uploader_;

  // Enterprise-specific reporting variables:
  // Keeps track of the state of the service for enterprise telemetry reporting.
  bool enterprise_enabled_ = false;

  SignalProcessors enterprise_signal_processors_;
  SignalSubscribers enterprise_signal_subscribers_;

  // Stores data on extensions with generated signals for enterprise reporting.
  ExtensionStore enterprise_extension_store_;

  // Used for periodic collection of enterprise telemetry reports.
  base::RepeatingTimer enterprise_timer_;

  // Indicates whether |Shutdown| has been called.
  bool is_shutdown_ = false;

  friend class ExtensionTelemetryServiceTest;
  friend class ExtensionTelemetryServiceBrowserTest;
  FRIEND_TEST_ALL_PREFIXES(ExtensionTelemetryServiceTest,
                           PersistsReportsOnInterval);
  FRIEND_TEST_ALL_PREFIXES(ExtensionTelemetryServiceTest,
                           MalformedPersistedFile);
  FRIEND_TEST_ALL_PREFIXES(ExtensionTelemetryServiceTest,
                           FileData_EnforcesCollectionDurationLimit);

  base::WeakPtrFactory<ExtensionTelemetryService> weak_factory_{this};
};

}  // namespace safe_browsing

#endif  // CHROME_BROWSER_SAFE_BROWSING_EXTENSION_TELEMETRY_EXTENSION_TELEMETRY_SERVICE_H_