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
|
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
import { XPCOMUtils } from "resource://gre/modules/XPCOMUtils.sys.mjs";
import { ExtensionUtils } from "resource://gre/modules/ExtensionUtils.sys.mjs";
const lazy = {};
ChromeUtils.defineESModuleGetters(lazy, {
ExtensionParent: "resource://gre/modules/ExtensionParent.sys.mjs",
});
XPCOMUtils.defineLazyGetter(lazy, "tabTracker", () => {
return lazy.ExtensionParent.apiManager.global.tabTracker;
});
var { DefaultMap } = ExtensionUtils;
const MSG_SET_ENABLED = "Extension:ActivityLog:SetEnabled";
const MSG_LOG = "Extension:ActivityLog:DoLog";
export const ExtensionActivityLog = {
initialized: false,
// id => Set(callbacks)
listeners: new DefaultMap(() => new Set()),
watchedIds: new Set(),
init() {
if (this.initialized) {
return;
}
this.initialized = true;
Services.ppmm.sharedData.set("extensions/logging", this.watchedIds);
Services.ppmm.addMessageListener(MSG_LOG, this);
},
/**
* Notify all listeners of an extension activity.
*
* @param {string} id The ID of the extension that caused the activity.
* @param {string} viewType The view type the activity is in.
* @param {string} type The type of the activity.
* @param {string} name The API name or path.
* @param {object} data Activity specific data.
* @param {string} timeStamp The timestamp for the activity.
*/
log(id, viewType, type, name, data, timeStamp) {
if (!this.initialized) {
return;
}
let callbacks = this.listeners.get(id);
if (callbacks) {
if (!timeStamp) {
timeStamp = new Date();
}
for (let callback of callbacks) {
try {
callback({ id, viewType, timeStamp, type, name, data });
} catch (e) {
Cu.reportError(e);
}
}
}
},
addListener(id, callback) {
this.init();
let callbacks = this.listeners.get(id);
if (callbacks.size === 0) {
this.watchedIds.add(id);
Services.ppmm.sharedData.set("extensions/logging", this.watchedIds);
Services.ppmm.sharedData.flush();
Services.ppmm.broadcastAsyncMessage(MSG_SET_ENABLED, { id, value: true });
}
callbacks.add(callback);
},
removeListener(id, callback) {
let callbacks = this.listeners.get(id);
if (callbacks.size > 0) {
callbacks.delete(callback);
if (callbacks.size === 0) {
this.watchedIds.delete(id);
Services.ppmm.sharedData.set("extensions/logging", this.watchedIds);
Services.ppmm.sharedData.flush();
Services.ppmm.broadcastAsyncMessage(MSG_SET_ENABLED, {
id,
value: false,
});
}
}
},
receiveMessage({ name, data }) {
if (name === MSG_LOG) {
let { viewType, browsingContextId } = data;
if (browsingContextId && (!viewType || viewType == "tab")) {
let browser =
BrowsingContext.get(browsingContextId).top.embedderElement;
let browserData = lazy.tabTracker.getBrowserData(browser);
if (browserData && browserData.tabId !== undefined) {
data.data.tabId = browserData.tabId;
}
}
this.log(
data.id,
data.viewType,
data.type,
data.name,
data.data,
new Date(data.timeStamp)
);
}
},
};
|