|
1 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
2 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
4 |
|
5 "use strict"; |
|
6 |
|
7 const {interfaces: Ci, utils: Cu} = Components; |
|
8 |
|
9 Cu.import("resource://gre/modules/XPCOMUtils.jsm"); |
|
10 Cu.import("resource://gre/modules/Services.jsm"); |
|
11 Cu.import("resource://gre/modules/Preferences.jsm"); |
|
12 |
|
13 XPCOMUtils.defineLazyModuleGetter(this, "Experiments", |
|
14 "resource:///modules/experiments/Experiments.jsm"); |
|
15 XPCOMUtils.defineLazyModuleGetter(this, "OS", |
|
16 "resource://gre/modules/osfile.jsm"); |
|
17 XPCOMUtils.defineLazyModuleGetter(this, "CommonUtils", |
|
18 "resource://services-common/utils.js"); |
|
19 |
|
20 const PREF_EXPERIMENTS_ENABLED = "experiments.enabled"; |
|
21 const PREF_ACTIVE_EXPERIMENT = "experiments.activeExperiment"; // whether we have an active experiment |
|
22 const PREF_HEALTHREPORT_ENABLED = "datareporting.healthreport.service.enabled"; |
|
23 const PREF_TELEMETRY_ENABLED = "toolkit.telemetry.enabled"; |
|
24 const DELAY_INIT_MS = 30 * 1000; |
|
25 |
|
26 XPCOMUtils.defineLazyGetter( |
|
27 this, "gPrefs", () => { |
|
28 return new Preferences(); |
|
29 }); |
|
30 |
|
31 XPCOMUtils.defineLazyGetter( |
|
32 this, "gExperimentsEnabled", () => { |
|
33 return gPrefs.get(PREF_EXPERIMENTS_ENABLED, false) && |
|
34 gPrefs.get(PREF_TELEMETRY_ENABLED, false) && |
|
35 gPrefs.get(PREF_HEALTHREPORT_ENABLED, false); |
|
36 }); |
|
37 |
|
38 XPCOMUtils.defineLazyGetter( |
|
39 this, "gActiveExperiment", () => { |
|
40 return gPrefs.get(PREF_ACTIVE_EXPERIMENT); |
|
41 }); |
|
42 |
|
43 function ExperimentsService() { |
|
44 this._initialized = false; |
|
45 this._delayedInitTimer = null; |
|
46 } |
|
47 |
|
48 ExperimentsService.prototype = { |
|
49 classID: Components.ID("{f7800463-3b97-47f9-9341-b7617e6d8d49}"), |
|
50 QueryInterface: XPCOMUtils.generateQI([Ci.nsITimerCallback, Ci.nsIObserver]), |
|
51 |
|
52 notify: function (timer) { |
|
53 if (!gExperimentsEnabled) { |
|
54 return; |
|
55 } |
|
56 if (OS.Constants.Path.profileDir === undefined) { |
|
57 throw Error("Update timer fired before profile was initialized?"); |
|
58 } |
|
59 Experiments.instance().updateManifest(); |
|
60 }, |
|
61 |
|
62 _delayedInit: function () { |
|
63 if (!this._initialized) { |
|
64 this._initialized = true; |
|
65 Experiments.instance(); // for side effects |
|
66 } |
|
67 }, |
|
68 |
|
69 observe: function (subject, topic, data) { |
|
70 switch (topic) { |
|
71 case "profile-after-change": |
|
72 if (gExperimentsEnabled) { |
|
73 Services.obs.addObserver(this, "quit-application", false); |
|
74 Services.obs.addObserver(this, "sessionstore-state-finalized", false); |
|
75 Services.obs.addObserver(this, "EM-loaded", false); |
|
76 |
|
77 if (gActiveExperiment) { |
|
78 this._initialized = true; |
|
79 Experiments.instance(); // for side effects |
|
80 } |
|
81 } |
|
82 break; |
|
83 case "sessionstore-state-finalized": |
|
84 if (!this._initialized) { |
|
85 CommonUtils.namedTimer(this._delayedInit, DELAY_INIT_MS, this, "_delayedInitTimer"); |
|
86 } |
|
87 break; |
|
88 case "EM-loaded": |
|
89 if (!this._initialized) { |
|
90 Experiments.instance(); // for side effects |
|
91 this._initialized = true; |
|
92 |
|
93 if (this._delayedInitTimer) { |
|
94 this._delayedInitTimer.clear(); |
|
95 } |
|
96 } |
|
97 break; |
|
98 case "quit-application": |
|
99 Services.obs.removeObserver(this, "quit-application"); |
|
100 Services.obs.removeObserver(this, "sessionstore-state-finalized"); |
|
101 Services.obs.removeObserver(this, "EM-loaded"); |
|
102 if (this._delayedInitTimer) { |
|
103 this._delayedInitTimer.clear(); |
|
104 } |
|
105 break; |
|
106 } |
|
107 }, |
|
108 }; |
|
109 |
|
110 this.NSGetFactory = XPCOMUtils.generateNSGetFactory([ExperimentsService]); |