mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1106896 - Improve debug and error reporting in mozSettings. r=qdot
We break down the logging capabilities into two classes: debug and verbose. Verbose will help to track everything that happens, while debug should just report error cases. We also augment memory reports with values to help tracking potential issues like: queue blockage, leaking, etc.
This commit is contained in:
parent
d63a3c41e8
commit
b055fb374c
@ -1059,3 +1059,13 @@ pref("dom.udpsocket.enabled", true);
|
||||
|
||||
// Enable TV Manager API
|
||||
pref("dom.tv.enabled", true);
|
||||
|
||||
pref("dom.mozSettings.SettingsDB.debug.enabled", true);
|
||||
pref("dom.mozSettings.SettingsManager.debug.enabled", true);
|
||||
pref("dom.mozSettings.SettingsRequestManager.debug.enabled", true);
|
||||
pref("dom.mozSettings.SettingsService.debug.enabled", true);
|
||||
|
||||
pref("dom.mozSettings.SettingsDB.verbose.enabled", false);
|
||||
pref("dom.mozSettings.SettingsManager.verbose.enabled", false);
|
||||
pref("dom.mozSettings.SettingsRequestManager.verbose.enabled", false);
|
||||
pref("dom.mozSettings.SettingsService.verbose.enabled", false);
|
||||
|
@ -13,9 +13,18 @@ Cu.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
this.EXPORTED_SYMBOLS = ["SettingsDB", "SETTINGSDB_NAME", "SETTINGSSTORE_NAME"];
|
||||
|
||||
const DEBUG = false;
|
||||
let DEBUG = false;
|
||||
let VERBOSE = false;
|
||||
|
||||
try {
|
||||
DEBUG =
|
||||
Services.prefs.getBoolPref("dom.mozSettings.SettingsDB.debug.enabled");
|
||||
VERBOSE =
|
||||
Services.prefs.getBoolPref("dom.mozSettings.SettingsDB.verbose.enabled");
|
||||
} catch (ex) { }
|
||||
|
||||
function debug(s) {
|
||||
if (DEBUG) dump("-*- SettingsDB: " + s + "\n");
|
||||
dump("-*- SettingsDB: " + s + "\n");
|
||||
}
|
||||
|
||||
const TYPED_ARRAY_THINGS = new Set([
|
||||
@ -48,13 +57,13 @@ SettingsDB.prototype = {
|
||||
let objectStore;
|
||||
if (aOldVersion == 0) {
|
||||
objectStore = aDb.createObjectStore(SETTINGSSTORE_NAME, { keyPath: "settingName" });
|
||||
if (DEBUG) debug("Created object stores");
|
||||
if (VERBOSE) debug("Created object stores");
|
||||
} else if (aOldVersion == 1) {
|
||||
if (DEBUG) debug("Get object store for upgrade and remove old index");
|
||||
if (VERBOSE) debug("Get object store for upgrade and remove old index");
|
||||
objectStore = aTransaction.objectStore(SETTINGSSTORE_NAME);
|
||||
objectStore.deleteIndex("settingValue");
|
||||
} else {
|
||||
if (DEBUG) debug("Get object store for upgrade");
|
||||
if (VERBOSE) debug("Get object store for upgrade");
|
||||
objectStore = aTransaction.objectStore(SETTINGSSTORE_NAME);
|
||||
}
|
||||
|
||||
@ -94,7 +103,7 @@ SettingsDB.prototype = {
|
||||
if (cursor) {
|
||||
let value = cursor.value;
|
||||
if (value.settingName in settings) {
|
||||
if (DEBUG) debug("Upgrade " +settings[value.settingName]);
|
||||
if (VERBOSE) debug("Upgrade " +settings[value.settingName]);
|
||||
value.defaultValue = this.prepareValue(settings[value.settingName]);
|
||||
delete settings[value.settingName];
|
||||
if ("settingValue" in value) {
|
||||
@ -116,7 +125,7 @@ SettingsDB.prototype = {
|
||||
} else {
|
||||
for (let name in settings) {
|
||||
let value = this.prepareValue(settings[name]);
|
||||
if (DEBUG) debug("Set new:" + name +", " + value);
|
||||
if (VERBOSE) debug("Set new:" + name +", " + value);
|
||||
objectStore.add({ settingName: name, defaultValue: value, userValue: undefined });
|
||||
}
|
||||
}
|
||||
|
@ -4,8 +4,19 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
const DEBUG = false;
|
||||
function debug(s) { dump("-*- SettingsManager: " + s + "\n"); }
|
||||
let DEBUG = false;
|
||||
let VERBOSE = false;
|
||||
|
||||
try {
|
||||
DEBUG =
|
||||
Services.prefs.getBoolPref("dom.mozSettings.SettingsManager.debug.enabled");
|
||||
VERBOSE =
|
||||
Services.prefs.getBoolPref("dom.mozSettings.SettingsManager.verbose.enabled");
|
||||
} catch (ex) { }
|
||||
|
||||
function debug(s) {
|
||||
dump("-*- SettingsManager: " + s + "\n");
|
||||
}
|
||||
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
@ -45,7 +56,7 @@ XPCOMUtils.defineLazyServiceGetter(this, "uuidgen",
|
||||
*/
|
||||
|
||||
function SettingsLock(aSettingsManager) {
|
||||
if (DEBUG) debug("settings lock init");
|
||||
if (VERBOSE) debug("settings lock init");
|
||||
this._open = true;
|
||||
this._settingsManager = aSettingsManager;
|
||||
this._id = uuidgen.generateUUID().toString();
|
||||
@ -90,15 +101,15 @@ SettingsLock.prototype = {
|
||||
},
|
||||
|
||||
_closeHelper: function() {
|
||||
if (DEBUG) debug("closing lock " + this._id);
|
||||
if (VERBOSE) debug("closing lock " + this._id);
|
||||
this._open = false;
|
||||
this._closeCalled = false;
|
||||
if (!this._requests || Object.keys(this._requests).length == 0) {
|
||||
if (DEBUG) debug("Requests exhausted, finalizing " + this._id);
|
||||
if (VERBOSE) debug("Requests exhausted, finalizing " + this._id);
|
||||
this._settingsManager.unregisterLock(this._id);
|
||||
this.sendMessage("Settings:Finalize", {lockID: this._id});
|
||||
} else {
|
||||
if (DEBUG) debug("Requests left: " + Object.keys(this._requests).length);
|
||||
if (VERBOSE) debug("Requests left: " + Object.keys(this._requests).length);
|
||||
this.sendMessage("Settings:Run", {lockID: this._id});
|
||||
}
|
||||
},
|
||||
@ -135,7 +146,7 @@ SettingsLock.prototype = {
|
||||
if (msg.lockID != this._id) {
|
||||
return;
|
||||
}
|
||||
if (DEBUG) debug("receiveMessage (" + this._id + "): " + aMessage.name);
|
||||
if (VERBOSE) debug("receiveMessage (" + this._id + "): " + aMessage.name);
|
||||
|
||||
// Finalizing a transaction does not return a request ID since we are
|
||||
// supposed to fire callbacks.
|
||||
@ -148,7 +159,7 @@ SettingsLock.prototype = {
|
||||
let event;
|
||||
switch (aMessage.name) {
|
||||
case "Settings:Finalize:OK":
|
||||
if (DEBUG) debug("Lock finalize ok: " + this._id);
|
||||
if (VERBOSE) debug("Lock finalize ok: " + this._id);
|
||||
event = new this._window.MozSettingsTransactionEvent("settingstransactionsuccess", {});
|
||||
this.__DOM_IMPL__.dispatchEvent(event);
|
||||
this.destroyDOMRequestHelper();
|
||||
@ -183,7 +194,7 @@ SettingsLock.prototype = {
|
||||
Services.tm.currentThread.dispatch(this._closeHelper.bind(this), Ci.nsIThread.DISPATCH_NORMAL);
|
||||
this._closeCalled = true;
|
||||
}
|
||||
if (DEBUG) debug("receiveMessage: " + aMessage.name);
|
||||
if (VERBOSE) debug("receiveMessage: " + aMessage.name);
|
||||
switch (aMessage.name) {
|
||||
case "Settings:Get:OK":
|
||||
for (let i in msg.settings) {
|
||||
@ -211,7 +222,7 @@ SettingsLock.prototype = {
|
||||
},
|
||||
|
||||
get: function get(aName) {
|
||||
if (DEBUG) debug("get (" + this._id + "): " + aName);
|
||||
if (VERBOSE) debug("get (" + this._id + "): " + aName);
|
||||
if (!this._open) {
|
||||
dump("Settings lock not open!\n");
|
||||
throw Components.results.NS_ERROR_ABORT;
|
||||
@ -225,7 +236,7 @@ SettingsLock.prototype = {
|
||||
},
|
||||
|
||||
set: function set(aSettings) {
|
||||
if (DEBUG) debug("send: " + JSON.stringify(aSettings));
|
||||
if (VERBOSE) debug("send: " + JSON.stringify(aSettings));
|
||||
if (!this._open) {
|
||||
throw "Settings lock not open";
|
||||
}
|
||||
@ -238,7 +249,7 @@ SettingsLock.prototype = {
|
||||
},
|
||||
|
||||
clear: function clear() {
|
||||
if (DEBUG) if (DEBUG) debug("clear");
|
||||
if (VERBOSE) debug("clear");
|
||||
if (!this._open) {
|
||||
throw "Settings lock not open";
|
||||
}
|
||||
@ -260,6 +271,8 @@ function SettingsManager() {
|
||||
this._callbacks = null;
|
||||
this._isRegistered = false;
|
||||
this._locks = [];
|
||||
this._createdLocks = 0;
|
||||
this._unregisteredLocks = 0;
|
||||
}
|
||||
|
||||
SettingsManager.prototype = {
|
||||
@ -278,26 +291,28 @@ SettingsManager.prototype = {
|
||||
|
||||
createLock: function() {
|
||||
let lock = new SettingsLock(this);
|
||||
if (DEBUG) debug("creating lock " + lock._id);
|
||||
if (VERBOSE) debug("creating lock " + lock._id);
|
||||
this._locks.push(lock._id);
|
||||
this._createdLocks++;
|
||||
return lock;
|
||||
},
|
||||
|
||||
unregisterLock: function(aLockID) {
|
||||
let lock_index = this._locks.indexOf(aLockID);
|
||||
if (lock_index != -1) {
|
||||
if (DEBUG) debug("Unregistering lock " + aLockID);
|
||||
if (VERBOSE) debug("Unregistering lock " + aLockID);
|
||||
this._locks.splice(lock_index, 1);
|
||||
this._unregisteredLocks++;
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
receiveMessage: function(aMessage) {
|
||||
if (DEBUG) debug("Settings::receiveMessage: " + aMessage.name);
|
||||
if (VERBOSE) debug("Settings::receiveMessage: " + aMessage.name);
|
||||
let msg = aMessage.json;
|
||||
|
||||
switch (aMessage.name) {
|
||||
case "Settings:Change:Return:OK":
|
||||
if (DEBUG) debug('data:' + msg.key + ':' + msg.value + '\n');
|
||||
if (VERBOSE) debug('data:' + msg.key + ':' + msg.value + '\n');
|
||||
|
||||
let event = new this._window.MozSettingsEvent("settingchange", this._wrap({
|
||||
settingName: msg.key,
|
||||
@ -306,12 +321,12 @@ SettingsManager.prototype = {
|
||||
this.__DOM_IMPL__.dispatchEvent(event);
|
||||
|
||||
if (this._callbacks && this._callbacks[msg.key]) {
|
||||
if (DEBUG) debug("observe callback called! " + msg.key + " " + this._callbacks[msg.key].length);
|
||||
if (VERBOSE) debug("observe callback called! " + msg.key + " " + this._callbacks[msg.key].length);
|
||||
this._callbacks[msg.key].forEach(function(cb) {
|
||||
cb(this._wrap({settingName: msg.key, settingValue: msg.value}));
|
||||
}.bind(this));
|
||||
} else {
|
||||
if (DEBUG) debug("no observers stored!");
|
||||
if (VERBOSE) debug("no observers stored!");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@ -325,7 +340,7 @@ SettingsManager.prototype = {
|
||||
checkMessageRegistration: function checkRegistration() {
|
||||
let handler = this.__DOM_IMPL__.getEventHandler("onsettingchange");
|
||||
if (!this._isRegistered) {
|
||||
if (DEBUG) debug("Registering for messages");
|
||||
if (VERBOSE) debug("Registering for messages");
|
||||
cpmm.sendAsyncMessage("Settings:RegisterForMessages",
|
||||
undefined,
|
||||
undefined,
|
||||
@ -334,7 +349,7 @@ SettingsManager.prototype = {
|
||||
} else {
|
||||
if ((!this._callbacks || Object.keys(this._callbacks).length == 0) &&
|
||||
!handler) {
|
||||
if (DEBUG) debug("Unregistering for messages");
|
||||
if (VERBOSE) debug("Unregistering for messages");
|
||||
cpmm.sendAsyncMessage("Settings:UnregisterForMessages",
|
||||
undefined,
|
||||
undefined,
|
||||
@ -344,9 +359,9 @@ SettingsManager.prototype = {
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
addObserver: function addObserver(aName, aCallback) {
|
||||
if (DEBUG) debug("addObserver " + aName);
|
||||
if (VERBOSE) debug("addObserver " + aName);
|
||||
if (!this._callbacks) {
|
||||
this._callbacks = {};
|
||||
}
|
||||
@ -359,7 +374,7 @@ SettingsManager.prototype = {
|
||||
},
|
||||
|
||||
removeObserver: function removeObserver(aName, aCallback) {
|
||||
if (DEBUG) debug("deleteObserver " + aName);
|
||||
if (VERBOSE) debug("deleteObserver " + aName);
|
||||
if (this._callbacks && this._callbacks[aName]) {
|
||||
let index = this._callbacks[aName].indexOf(aCallback);
|
||||
if (index != -1) {
|
||||
@ -368,16 +383,16 @@ SettingsManager.prototype = {
|
||||
delete this._callbacks[aName];
|
||||
}
|
||||
} else {
|
||||
if (DEBUG) debug("Callback not found for: " + aName);
|
||||
if (VERBOSE) debug("Callback not found for: " + aName);
|
||||
}
|
||||
} else {
|
||||
if (DEBUG) debug("No observers stored for " + aName);
|
||||
if (VERBOSE) debug("No observers stored for " + aName);
|
||||
}
|
||||
this.checkMessageRegistration();
|
||||
},
|
||||
|
||||
init: function(aWindow) {
|
||||
if (DEBUG) debug("SettingsManager init");
|
||||
if (VERBOSE) debug("SettingsManager init");
|
||||
mrm.registerStrongReporter(this);
|
||||
cpmm.addMessageListener("Settings:Change:Return:OK", this);
|
||||
Services.obs.addObserver(this, "inner-window-destroyed", false);
|
||||
@ -387,7 +402,7 @@ SettingsManager.prototype = {
|
||||
},
|
||||
|
||||
observe: function(aSubject, aTopic, aData) {
|
||||
if (DEBUG) debug("Topic: " + aTopic);
|
||||
if (VERBOSE) debug("Topic: " + aTopic);
|
||||
if (aTopic === "inner-window-destroyed") {
|
||||
let wId = aSubject.QueryInterface(Ci.nsISupportsPRUint64).data;
|
||||
if (wId === this.innerWindowID) {
|
||||
@ -415,10 +430,34 @@ SettingsManager.prototype = {
|
||||
aCallback.callback("", path,
|
||||
Ci.nsIMemoryReporter.KIND_OTHER,
|
||||
Ci.nsIMemoryReporter.UNITS_COUNT,
|
||||
this._callbacks[topic].length,
|
||||
length,
|
||||
"The number of settings observers for this topic.",
|
||||
aData);
|
||||
}
|
||||
|
||||
aCallback.callback("",
|
||||
"settings-locks/alive",
|
||||
Ci.nsIMemoryReporter.KIND_OTHER,
|
||||
Ci.nsIMemoryReporter.UNITS_COUNT,
|
||||
this._locks.length,
|
||||
"The number of locks that are currently alives.",
|
||||
aData);
|
||||
|
||||
aCallback.callback("",
|
||||
"settings-locks/created",
|
||||
Ci.nsIMemoryReporter.KIND_OTHER,
|
||||
Ci.nsIMemoryReporter.UNITS_COUNT,
|
||||
this._createdLocks,
|
||||
"The number of locks that were created.",
|
||||
aData);
|
||||
|
||||
aCallback.callback("",
|
||||
"settings-locks/deleted",
|
||||
Ci.nsIMemoryReporter.KIND_OTHER,
|
||||
Ci.nsIMemoryReporter.UNITS_COUNT,
|
||||
this._unregisteredLocks,
|
||||
"The number of locks that were deleted.",
|
||||
aData);
|
||||
},
|
||||
|
||||
cleanup: function() {
|
||||
|
@ -4,8 +4,18 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
const DEBUG = false;
|
||||
let DEBUG = false;
|
||||
let VERBOSE = false;
|
||||
|
||||
try {
|
||||
DEBUG =
|
||||
Services.prefs.getBoolPref("dom.mozSettings.SettingsRequestManager.debug.enabled");
|
||||
VERBOSE =
|
||||
Services.prefs.getBoolPref("dom.mozSettings.SettingsRequestManager.verbose.enabled");
|
||||
} catch (ex) { }
|
||||
|
||||
function debug(s) { dump("-*- SettingsRequestManager: " + s + "\n"); }
|
||||
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
const Cu = Components.utils;
|
||||
@ -33,6 +43,9 @@ const kAllSettingsWritePermission = "settings" + kSettingsWriteSuffix;
|
||||
const kSomeSettingsReadPermission = "settings-api" + kSettingsReadSuffix;
|
||||
const kSomeSettingsWritePermission = "settings-api" + kSettingsWriteSuffix;
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "mrm",
|
||||
"@mozilla.org/memory-reporter-manager;1",
|
||||
"nsIMemoryReporterManager");
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "ppmm",
|
||||
"@mozilla.org/parentprocessmessagemanager;1",
|
||||
"nsIMessageBroadcaster");
|
||||
@ -102,7 +115,7 @@ function SettingsLockInfo(aDB, aMsgMgr, aLockID, aIsServiceLock, aWindowID) {
|
||||
// Lets us know if this lock has been used to clear at any point.
|
||||
hasCleared: false,
|
||||
getObjectStore: function(aPrincipal) {
|
||||
if (DEBUG) debug("Getting transaction for " + this.lockID);
|
||||
if (VERBOSE) debug("Getting transaction for " + this.lockID);
|
||||
let store;
|
||||
// Test for transaction validity via trying to get the
|
||||
// datastore. If it doesn't work, assume the transaction is
|
||||
@ -112,8 +125,9 @@ function SettingsLockInfo(aDB, aMsgMgr, aLockID, aIsServiceLock, aWindowID) {
|
||||
store = this._transaction.objectStore(SETTINGSSTORE_NAME);
|
||||
} catch (e) {
|
||||
if (e.name == "InvalidStateError") {
|
||||
if (DEBUG) debug("Current transaction for " + this.lockID + " closed, trying to create new one.");
|
||||
if (VERBOSE) debug("Current transaction for " + this.lockID + " closed, trying to create new one.");
|
||||
} else {
|
||||
if (DEBUG) debug("Unexpected exception, throwing: " + e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
@ -123,14 +137,14 @@ function SettingsLockInfo(aDB, aMsgMgr, aLockID, aIsServiceLock, aWindowID) {
|
||||
// it means we don't have to do our own transaction order
|
||||
// bookkeeping.
|
||||
if (!SettingsPermissions.hasSomeWritePermission(aPrincipal)) {
|
||||
if (DEBUG) debug("Making READONLY transaction for " + this.lockID);
|
||||
if (VERBOSE) debug("Making READONLY transaction for " + this.lockID);
|
||||
this._transaction = aDB._db.transaction(SETTINGSSTORE_NAME, "readonly");
|
||||
} else {
|
||||
if (DEBUG) debug("Making READWRITE transaction for " + this.lockID);
|
||||
if (VERBOSE) debug("Making READWRITE transaction for " + this.lockID);
|
||||
this._transaction = aDB._db.transaction(SETTINGSSTORE_NAME, "readwrite");
|
||||
}
|
||||
this._transaction.oncomplete = function() {
|
||||
if (DEBUG) debug("Transaction for lock " + this.lockID + " closed");
|
||||
if (VERBOSE) debug("Transaction for lock " + this.lockID + " closed");
|
||||
}.bind(this);
|
||||
this._transaction.onabort = function () {
|
||||
if (DEBUG) debug("Transaction for lock " + this.lockID + " aborted");
|
||||
@ -143,6 +157,7 @@ function SettingsLockInfo(aDB, aMsgMgr, aLockID, aIsServiceLock, aWindowID) {
|
||||
if (DEBUG) debug("Cannot create objectstore on transaction for " + this.lockID);
|
||||
return null;
|
||||
} else {
|
||||
if (DEBUG) debug("Unexpected exception, throwing: " + e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
@ -166,15 +181,17 @@ let SettingsRequestManager = {
|
||||
settingsLockQueue: [],
|
||||
children: [],
|
||||
mmPrincipals: new Map(),
|
||||
tasksConsumed: 0,
|
||||
|
||||
init: function() {
|
||||
if (DEBUG) debug("init");
|
||||
if (VERBOSE) debug("init");
|
||||
this.settingsDB.init();
|
||||
this.messages.forEach((function(msgName) {
|
||||
ppmm.addMessageListener(msgName, this);
|
||||
}).bind(this));
|
||||
Services.obs.addObserver(this, kXpcomShutdownObserverTopic, false);
|
||||
Services.obs.addObserver(this, kInnerWindowDestroyed, false);
|
||||
mrm.registerStrongReporter(this);
|
||||
},
|
||||
|
||||
_serializePreservingBinaries: function _serializePreservingBinaries(aObject) {
|
||||
@ -209,7 +226,7 @@ let SettingsRequestManager = {
|
||||
},
|
||||
|
||||
queueTask: function(aOperation, aData, aPrincipal) {
|
||||
if (DEBUG) debug("Queueing task: " + aOperation);
|
||||
if (VERBOSE) debug("Queueing task: " + aOperation);
|
||||
|
||||
let defer = {};
|
||||
|
||||
@ -246,7 +263,7 @@ let SettingsRequestManager = {
|
||||
// get, which means it will resolves afer the rest of the calls
|
||||
// queued to the DB.
|
||||
queueTaskReturn: function(aTask, aReturnValue) {
|
||||
if (DEBUG) debug("Making task queuing transaction request.");
|
||||
if (VERBOSE) debug("Making task queuing transaction request.");
|
||||
let data = aTask.data;
|
||||
let lock = this.lockInfo[data.lockID];
|
||||
let store = lock.getObjectStore(aTask.principal);
|
||||
@ -278,7 +295,7 @@ let SettingsRequestManager = {
|
||||
},
|
||||
|
||||
taskGet: function(aTask) {
|
||||
if (DEBUG) debug("Running Get task on lock " + aTask.data.lockID);
|
||||
if (VERBOSE) debug("Running Get task on lock " + aTask.data.lockID);
|
||||
|
||||
// Check that we have permissions for getting the value
|
||||
let data = aTask.data;
|
||||
@ -307,21 +324,21 @@ let SettingsRequestManager = {
|
||||
|
||||
// If the value was set during this transaction, use the cached value
|
||||
if (data.name in lock.queuedSets) {
|
||||
if (DEBUG) debug("Returning cached set value " + lock.queuedSets[data.name] + " for " + data.name);
|
||||
if (VERBOSE) debug("Returning cached set value " + lock.queuedSets[data.name] + " for " + data.name);
|
||||
let local_results = {};
|
||||
local_results[data.name] = lock.queuedSets[data.name];
|
||||
return this.queueTaskReturn(aTask, {task: aTask, results: local_results});
|
||||
}
|
||||
|
||||
// Create/Get transaction and make request
|
||||
if (DEBUG) debug("Making get transaction request for " + data.name);
|
||||
if (VERBOSE) debug("Making get transaction request for " + data.name);
|
||||
let store = lock.getObjectStore(aTask.principal);
|
||||
if (!store) {
|
||||
if (DEBUG) debug("Rejecting Get task on lock " + aTask.data.lockID);
|
||||
return Promise.reject({task: aTask, error: "Cannot get object store"});
|
||||
}
|
||||
|
||||
if (DEBUG) debug("Making get request for " + data.name);
|
||||
if (VERBOSE) debug("Making get request for " + data.name);
|
||||
let getReq = (data.name === "*") ? store.mozGetAll() : store.mozGetAll(data.name);
|
||||
|
||||
let defer = {};
|
||||
@ -331,11 +348,11 @@ let SettingsRequestManager = {
|
||||
});
|
||||
|
||||
getReq.onsuccess = function(event) {
|
||||
if (DEBUG) debug("Request for '" + data.name + "' successful. " +
|
||||
if (VERBOSE) debug("Request for '" + data.name + "' successful. " +
|
||||
"Record count: " + event.target.result.length);
|
||||
|
||||
if (event.target.result.length == 0) {
|
||||
if (DEBUG) debug("MOZSETTINGS-GET-WARNING: " + data.name + " is not in the database.\n");
|
||||
if (VERBOSE) debug("MOZSETTINGS-GET-WARNING: " + data.name + " is not in the database.\n");
|
||||
}
|
||||
|
||||
let results = {};
|
||||
@ -343,7 +360,7 @@ let SettingsRequestManager = {
|
||||
for (let i in event.target.result) {
|
||||
let result = event.target.result[i];
|
||||
let name = result.settingName;
|
||||
if (DEBUG) debug(name + ": " + result.userValue +", " + result.defaultValue);
|
||||
if (VERBOSE) debug(name + ": " + result.userValue +", " + result.defaultValue);
|
||||
let value = result.userValue !== undefined ? result.userValue : result.defaultValue;
|
||||
results[name] = value;
|
||||
}
|
||||
@ -391,7 +408,7 @@ let SettingsRequestManager = {
|
||||
|
||||
for (let i = 0; i < keys.length; i++) {
|
||||
let key = keys[i];
|
||||
if (DEBUG) debug("key: " + key + ", val: " + JSON.stringify(data.settings[key]) + ", type: " + typeof(data.settings[key]));
|
||||
if (VERBOSE) debug("key: " + key + ", val: " + JSON.stringify(data.settings[key]) + ", type: " + typeof(data.settings[key]));
|
||||
lock.queuedSets[key] = data.settings[key];
|
||||
}
|
||||
|
||||
@ -410,13 +427,13 @@ let SettingsRequestManager = {
|
||||
if (aLockID == this.settingsLockQueue[0] || this.settingsLockQueue.length == 0) {
|
||||
// If a lock is currently at the head of the queue, run all tasks for
|
||||
// it.
|
||||
if (DEBUG) debug("Start running tasks for " + aLockID);
|
||||
if (VERBOSE) debug("Start running tasks for " + aLockID);
|
||||
this.queueConsume();
|
||||
} else {
|
||||
// If a lock isn't at the head of the queue, but requests to be run,
|
||||
// simply mark it as consumable, which means it will automatically run
|
||||
// once it comes to the head of the queue.
|
||||
if (DEBUG) debug("Queuing tasks for " + aLockID + " while waiting for " + this.settingsLockQueue[0]);
|
||||
if (VERBOSE) debug("Queuing tasks for " + aLockID + " while waiting for " + this.settingsLockQueue[0]);
|
||||
}
|
||||
},
|
||||
|
||||
@ -428,7 +445,7 @@ let SettingsRequestManager = {
|
||||
|
||||
finalizeSets: function(aTask) {
|
||||
let data = aTask.data;
|
||||
if (DEBUG) debug("Finalizing tasks for lock " + data.lockID);
|
||||
if (VERBOSE) debug("Finalizing tasks for lock " + data.lockID);
|
||||
let lock = this.lockInfo[data.lockID];
|
||||
|
||||
if (!lock) {
|
||||
@ -442,13 +459,13 @@ let SettingsRequestManager = {
|
||||
// If we have cleared, there is no reason to continue finalizing
|
||||
// this lock. Just resolve promise with task and move on.
|
||||
if (lock.hasCleared) {
|
||||
if (DEBUG) debug("Clear was called on lock, skipping finalize");
|
||||
if (VERBOSE) debug("Clear was called on lock, skipping finalize");
|
||||
this.removeLock(data.lockID);
|
||||
return Promise.resolve({task: aTask});
|
||||
}
|
||||
let keys = Object.getOwnPropertyNames(lock.queuedSets);
|
||||
if (keys.length === 0) {
|
||||
if (DEBUG) debug("Nothing to finalize. Exiting.");
|
||||
if (VERBOSE) debug("Nothing to finalize. Exiting.");
|
||||
this.removeLock(data.lockID);
|
||||
return Promise.resolve({task: aTask});
|
||||
}
|
||||
@ -466,7 +483,7 @@ let SettingsRequestManager = {
|
||||
let finalValues = {};
|
||||
for (let i = 0; i < keys.length; i++) {
|
||||
let key = keys[i];
|
||||
if (DEBUG) debug("key: " + key + ", val: " + lock.queuedSets[key] + ", type: " + typeof(lock.queuedSets[key]));
|
||||
if (VERBOSE) debug("key: " + key + ", val: " + lock.queuedSets[key] + ", type: " + typeof(lock.queuedSets[key]));
|
||||
let checkDefer = {};
|
||||
let checkPromise = new Promise(function(resolve, reject) {
|
||||
checkDefer.resolve = resolve;
|
||||
@ -482,7 +499,7 @@ let SettingsRequestManager = {
|
||||
let defaultValue;
|
||||
if (!event.target.result) {
|
||||
defaultValue = null;
|
||||
if (DEBUG) debug("MOZSETTINGS-GET-WARNING: " + key + " is not in the database.\n");
|
||||
if (VERBOSE) debug("MOZSETTINGS-GET-WARNING: " + key + " is not in the database.\n");
|
||||
} else {
|
||||
defaultValue = event.target.result.defaultValue;
|
||||
}
|
||||
@ -490,8 +507,8 @@ let SettingsRequestManager = {
|
||||
finalValues[key] = {defaultValue: defaultValue, userValue: userValue};
|
||||
let setReq = store.put(obj);
|
||||
setReq.onsuccess = function() {
|
||||
if (DEBUG) debug("Set successful!");
|
||||
if (DEBUG) debug("key: " + key + ", val: " + finalValues[key] + ", type: " + typeof(finalValues[key]));
|
||||
if (VERBOSE) debug("Set successful!");
|
||||
if (VERBOSE) debug("key: " + key + ", val: " + finalValues[key] + ", type: " + typeof(finalValues[key]));
|
||||
return checkDefer.resolve({task: aTask});
|
||||
};
|
||||
setReq.onerror = function() {
|
||||
@ -533,7 +550,7 @@ let SettingsRequestManager = {
|
||||
// even by certified apps, which is why it has its own permission
|
||||
// (settings-clear).
|
||||
taskClear: function(aTask) {
|
||||
if (DEBUG) debug("Clearing");
|
||||
if (VERBOSE) debug("Clearing");
|
||||
let data = aTask.data;
|
||||
let lock = this.lockInfo[data.lockID];
|
||||
|
||||
@ -578,7 +595,7 @@ let SettingsRequestManager = {
|
||||
},
|
||||
|
||||
ensureConnection : function() {
|
||||
if (DEBUG) debug("Ensuring Connection");
|
||||
if (VERBOSE) debug("Ensuring Connection");
|
||||
let defer = {};
|
||||
let promiseWrapper = new Promise(function(resolve, reject) {
|
||||
defer.resolve = resolve;
|
||||
@ -595,7 +612,7 @@ let SettingsRequestManager = {
|
||||
},
|
||||
|
||||
runTasks: function(aLockID) {
|
||||
if (DEBUG) debug("Running tasks for " + aLockID);
|
||||
if (VERBOSE) debug("Running tasks for " + aLockID);
|
||||
let lock = this.lockInfo[aLockID];
|
||||
if (!lock) {
|
||||
if (DEBUG) debug("Lock no longer alive, cannot run tasks");
|
||||
@ -604,7 +621,7 @@ let SettingsRequestManager = {
|
||||
let currentTask = lock.tasks.shift();
|
||||
let promises = [];
|
||||
while (currentTask) {
|
||||
if (DEBUG) debug("Running Operation " + currentTask.operation);
|
||||
if (VERBOSE) debug("Running Operation " + currentTask.operation);
|
||||
if (lock.finalizing) {
|
||||
// We should really never get to this point, but if we do,
|
||||
// fail every task that happens.
|
||||
@ -612,6 +629,7 @@ let SettingsRequestManager = {
|
||||
currentTask.defer.reject("Cannot call new task after finalizing");
|
||||
} else {
|
||||
let p;
|
||||
this.tasksConsumed++;
|
||||
switch (currentTask.operation) {
|
||||
case "get":
|
||||
p = this.taskGet(currentTask);
|
||||
@ -642,12 +660,12 @@ let SettingsRequestManager = {
|
||||
|
||||
consumeTasks: function() {
|
||||
if (this.settingsLockQueue.length == 0) {
|
||||
if (DEBUG) debug("Nothing to run!");
|
||||
if (VERBOSE) debug("Nothing to run!");
|
||||
return;
|
||||
}
|
||||
|
||||
let lockID = this.settingsLockQueue[0];
|
||||
if (DEBUG) debug("Consuming tasks for " + lockID);
|
||||
if (VERBOSE) debug("Consuming tasks for " + lockID);
|
||||
let lock = this.lockInfo[lockID];
|
||||
|
||||
// If a process dies, we should clean up after it via the
|
||||
@ -660,7 +678,7 @@ let SettingsRequestManager = {
|
||||
}
|
||||
|
||||
if (!lock.consumable || lock.tasks.length === 0) {
|
||||
if (DEBUG) debug("No more tasks to run or not yet consuamble.");
|
||||
if (VERBOSE) debug("No more tasks to run or not yet consuamble.");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -674,7 +692,7 @@ let SettingsRequestManager = {
|
||||
},
|
||||
|
||||
observe: function(aSubject, aTopic, aData) {
|
||||
if (DEBUG) debug("observe: " + aTopic);
|
||||
if (VERBOSE) debug("observe: " + aTopic);
|
||||
switch (aTopic) {
|
||||
case kXpcomShutdownObserverTopic:
|
||||
this.messages.forEach((function(msgName) {
|
||||
@ -682,6 +700,7 @@ let SettingsRequestManager = {
|
||||
}).bind(this));
|
||||
Services.obs.removeObserver(this, kXpcomShutdownObserverTopic);
|
||||
ppmm = null;
|
||||
mrm.unregisterStrongReporter(this);
|
||||
break;
|
||||
|
||||
case kInnerWindowDestroyed:
|
||||
@ -695,6 +714,34 @@ let SettingsRequestManager = {
|
||||
}
|
||||
},
|
||||
|
||||
collectReports: function(aCallback, aData, aAnonymize) {
|
||||
for (let lockId of Object.keys(this.lockInfo)) {
|
||||
let lock = this.lockInfo[lockId];
|
||||
let length = lock.tasks.length;
|
||||
|
||||
if (length === 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let path = "settings-locks/tasks/queue-length(id=" + lockId + ")";
|
||||
|
||||
aCallback.callback("", path,
|
||||
Ci.nsIMemoryReporter.KIND_OTHER,
|
||||
Ci.nsIMemoryReporter.UNITS_COUNT,
|
||||
length,
|
||||
"Tasks queue length for this lock",
|
||||
aData);
|
||||
}
|
||||
|
||||
aCallback.callback("",
|
||||
"settings-locks/tasks/processed",
|
||||
Ci.nsIMemoryReporter.KIND_OTHER,
|
||||
Ci.nsIMemoryReporter.UNITS_COUNT,
|
||||
this.tasksConsumed,
|
||||
"The number of tasks that were executed.",
|
||||
aData);
|
||||
},
|
||||
|
||||
sendSettingsChange: function(aKey, aValue, aIsServiceLock) {
|
||||
this.broadcastMessage("Settings:Change:Return:OK",
|
||||
{ key: aKey, value: aValue });
|
||||
@ -708,7 +755,7 @@ let SettingsRequestManager = {
|
||||
},
|
||||
|
||||
broadcastMessage: function broadcastMessage(aMsgName, aContent) {
|
||||
if (DEBUG) debug("Broadcast");
|
||||
if (VERBOSE) debug("Broadcast");
|
||||
this.children.forEach(function(msgMgr) {
|
||||
let principal = this.mmPrincipals.get(msgMgr);
|
||||
if (!principal) {
|
||||
@ -722,11 +769,11 @@ let SettingsRequestManager = {
|
||||
}
|
||||
}
|
||||
}.bind(this));
|
||||
if (DEBUG) debug("Finished Broadcasting");
|
||||
if (VERBOSE) debug("Finished Broadcasting");
|
||||
},
|
||||
|
||||
addObserver: function(aMsgMgr, aPrincipal) {
|
||||
if (DEBUG) debug("Add observer for " + aPrincipal.origin);
|
||||
if (VERBOSE) debug("Add observer for " + aPrincipal.origin);
|
||||
if (this.children.indexOf(aMsgMgr) == -1) {
|
||||
this.children.push(aMsgMgr);
|
||||
this.mmPrincipals.set(aMsgMgr, aPrincipal);
|
||||
@ -734,7 +781,7 @@ let SettingsRequestManager = {
|
||||
},
|
||||
|
||||
removeObserver: function(aMsgMgr) {
|
||||
if (DEBUG) {
|
||||
if (VERBOSE) {
|
||||
let principal = this.mmPrincipals.get(aMsgMgr);
|
||||
if (principal) {
|
||||
debug("Remove observer for " + principal.origin);
|
||||
@ -745,11 +792,11 @@ let SettingsRequestManager = {
|
||||
this.children.splice(index, 1);
|
||||
this.mmPrincipals.delete(aMsgMgr);
|
||||
}
|
||||
if (DEBUG) debug("Principal/MessageManager pairs left: " + this.mmPrincipals.size);
|
||||
if (VERBOSE) debug("Principal/MessageManager pairs left: " + this.mmPrincipals.size);
|
||||
},
|
||||
|
||||
removeLock: function(aLockID) {
|
||||
if (DEBUG) debug("Removing lock " + aLockID);
|
||||
if (VERBOSE) debug("Removing lock " + aLockID);
|
||||
if (this.lockInfo[aLockID]) {
|
||||
let transaction = this.lockInfo[aLockID]._transaction;
|
||||
if (transaction) {
|
||||
@ -757,8 +804,9 @@ let SettingsRequestManager = {
|
||||
transaction.abort();
|
||||
} catch (e) {
|
||||
if (e.name == "InvalidStateError") {
|
||||
if (DEBUG) debug("Transaction for " + aLockID + " closed already");
|
||||
if (VERBOSE) debug("Transaction for " + aLockID + " closed already");
|
||||
} else {
|
||||
if (DEBUG) debug("Unexpected exception, throwing: " + e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
@ -790,10 +838,10 @@ let SettingsRequestManager = {
|
||||
|
||||
enqueueForceFinalize: function(lock, principal) {
|
||||
if (!this.hasLockFinalizeTask(lock)) {
|
||||
if (DEBUG) debug("Alive lock has pending tasks: " + lock.lockID);
|
||||
if (VERBOSE) debug("Alive lock has pending tasks: " + lock.lockID);
|
||||
this.queueTask("finalize", {lockID: lock.lockID}, principal).then(
|
||||
function() {
|
||||
if (DEBUG) debug("Alive lock " + lock.lockID + " succeeded to force-finalize");
|
||||
if (VERBOSE) debug("Alive lock " + lock.lockID + " succeeded to force-finalize");
|
||||
},
|
||||
function(error) {
|
||||
if (DEBUG) debug("Alive lock " + lock.lockID + " failed to force-finalize due to error: " + error);
|
||||
@ -806,7 +854,7 @@ let SettingsRequestManager = {
|
||||
},
|
||||
|
||||
forceFinalizeChildLocksNonOOP: function(windowId) {
|
||||
if (DEBUG) debug("Forcing finalize on child locks, non OOP");
|
||||
if (VERBOSE) debug("Forcing finalize on child locks, non OOP");
|
||||
|
||||
for (let lockId of Object.keys(this.lockInfo)) {
|
||||
let lock = this.lockInfo[lockId];
|
||||
@ -818,7 +866,7 @@ let SettingsRequestManager = {
|
||||
},
|
||||
|
||||
forceFinalizeChildLocksOOP: function(aMsgMgr) {
|
||||
if (DEBUG) debug("Forcing finalize on child locks, OOP");
|
||||
if (VERBOSE) debug("Forcing finalize on child locks, OOP");
|
||||
|
||||
for (let lockId of Object.keys(this.lockInfo)) {
|
||||
let lock = this.lockInfo[lockId];
|
||||
@ -830,7 +878,7 @@ let SettingsRequestManager = {
|
||||
},
|
||||
|
||||
receiveMessage: function(aMessage) {
|
||||
if (DEBUG) debug("receiveMessage " + aMessage.name + ": " + JSON.stringify(aMessage.data));
|
||||
if (VERBOSE) debug("receiveMessage " + aMessage.name + ": " + JSON.stringify(aMessage.data));
|
||||
|
||||
let msg = aMessage.data;
|
||||
let mm = aMessage.target;
|
||||
@ -881,7 +929,7 @@ let SettingsRequestManager = {
|
||||
|
||||
switch (aMessage.name) {
|
||||
case "child-process-shutdown":
|
||||
if (DEBUG) debug("Child process shutdown received.");
|
||||
if (VERBOSE) debug("Child process shutdown received.");
|
||||
this.forceFinalizeChildLocksOOP(mm);
|
||||
this.removeObserver(mm);
|
||||
break;
|
||||
@ -898,7 +946,7 @@ let SettingsRequestManager = {
|
||||
this.removeObserver(mm);
|
||||
break;
|
||||
case "Settings:CreateLock":
|
||||
if (DEBUG) debug("Received CreateLock for " + msg.lockID + " from " + aMessage.principal.origin + " window: " + msg.windowID);
|
||||
if (VERBOSE) debug("Received CreateLock for " + msg.lockID + " from " + aMessage.principal.origin + " window: " + msg.windowID);
|
||||
// If we try to create a lock ID that collides with one
|
||||
// already in the system, consider it a security violation and
|
||||
// kill.
|
||||
@ -915,7 +963,7 @@ let SettingsRequestManager = {
|
||||
msg.windowID);
|
||||
break;
|
||||
case "Settings:Get":
|
||||
if (DEBUG) debug("Received getRequest from " + msg.lockID);
|
||||
if (VERBOSE) debug("Received getRequest from " + msg.lockID);
|
||||
this.queueTask("get", msg, aMessage.principal).then(function(settings) {
|
||||
returnMessage("Settings:Get:OK", {
|
||||
lockID: msg.lockID,
|
||||
@ -932,7 +980,7 @@ let SettingsRequestManager = {
|
||||
});
|
||||
break;
|
||||
case "Settings:Set":
|
||||
if (DEBUG) debug("Received Set Request from " + msg.lockID);
|
||||
if (VERBOSE) debug("Received Set Request from " + msg.lockID);
|
||||
this.queueTask("set", msg, aMessage.principal).then(function(settings) {
|
||||
returnMessage("Settings:Set:OK", {
|
||||
lockID: msg.lockID,
|
||||
@ -947,7 +995,7 @@ let SettingsRequestManager = {
|
||||
});
|
||||
break;
|
||||
case "Settings:Clear":
|
||||
if (DEBUG) debug("Received Clear Request from " + msg.lockID);
|
||||
if (VERBOSE) debug("Received Clear Request from " + msg.lockID);
|
||||
this.queueTask("clear", msg, aMessage.principal).then(function() {
|
||||
returnMessage("Settings:Clear:OK", {
|
||||
lockID: msg.lockID,
|
||||
@ -962,7 +1010,7 @@ let SettingsRequestManager = {
|
||||
});
|
||||
break;
|
||||
case "Settings:Finalize":
|
||||
if (DEBUG) debug("Received Finalize");
|
||||
if (VERBOSE) debug("Received Finalize");
|
||||
this.queueTask("finalize", msg, aMessage.principal).then(function() {
|
||||
returnMessage("Settings:Finalize:OK", {
|
||||
lockID: msg.lockID
|
||||
@ -976,7 +1024,7 @@ let SettingsRequestManager = {
|
||||
// YES THIS IS SUPPOSED TO FALL THROUGH. Finalize is considered a task
|
||||
// running situation, but it also needs to queue a task.
|
||||
case "Settings:Run":
|
||||
if (DEBUG) debug("Received Run");
|
||||
if (VERBOSE) debug("Received Run");
|
||||
this.startRunning(msg.lockID);
|
||||
break;
|
||||
default:
|
||||
|
@ -5,7 +5,16 @@
|
||||
"use strict"
|
||||
|
||||
/* static functions */
|
||||
const DEBUG = false;
|
||||
let DEBUG = false;
|
||||
let VERBOSE = false;
|
||||
|
||||
try {
|
||||
DEBUG =
|
||||
Services.prefs.getBoolPref("dom.mozSettings.SettingsService.debug.enabled");
|
||||
VERBOSE =
|
||||
Services.prefs.getBoolPref("dom.mozSettings.SettingsService.verbose.enabled");
|
||||
} catch (ex) { }
|
||||
|
||||
function debug(s) {
|
||||
dump("-*- SettingsService: " + s + "\n");
|
||||
}
|
||||
@ -39,14 +48,14 @@ function makeSettingsServiceRequest(aCallback, aName, aValue) {
|
||||
};
|
||||
|
||||
function SettingsServiceLock(aSettingsService, aTransactionCallback) {
|
||||
if (DEBUG) debug("settingsServiceLock constr!");
|
||||
if (VERBOSE) debug("settingsServiceLock constr!");
|
||||
this._open = true;
|
||||
this._settingsService = aSettingsService;
|
||||
this._id = uuidgen.generateUUID().toString();
|
||||
this._transactionCallback = aTransactionCallback;
|
||||
this._requests = {};
|
||||
let closeHelper = function() {
|
||||
if (DEBUG) debug("closing lock " + this._id);
|
||||
if (VERBOSE) debug("closing lock " + this._id);
|
||||
this._open = false;
|
||||
this.runOrFinalizeQueries();
|
||||
}.bind(this);
|
||||
@ -90,13 +99,13 @@ SettingsServiceLock.prototype = {
|
||||
if(msg.lockID != this._id) {
|
||||
return;
|
||||
}
|
||||
if (DEBUG) debug("receiveMessage (" + this._id + "): " + aMessage.name);
|
||||
if (VERBOSE) debug("receiveMessage (" + this._id + "): " + aMessage.name);
|
||||
// Finalizing a transaction does not return a request ID since we are
|
||||
// supposed to fire callbacks.
|
||||
if (!msg.requestID) {
|
||||
switch (aMessage.name) {
|
||||
case "Settings:Finalize:OK":
|
||||
if (DEBUG) debug("Lock finalize ok!");
|
||||
if (VERBOSE) debug("Lock finalize ok!");
|
||||
this.callTransactionHandle();
|
||||
break;
|
||||
case "Settings:Finalize:KO":
|
||||
@ -149,7 +158,7 @@ SettingsServiceLock.prototype = {
|
||||
},
|
||||
|
||||
get: function get(aName, aCallback) {
|
||||
if (DEBUG) debug("get (" + this._id + "): " + aName);
|
||||
if (VERBOSE) debug("get (" + this._id + "): " + aName);
|
||||
if (!this._open) {
|
||||
dump("Settings lock not open!\n");
|
||||
throw Components.results.NS_ERROR_ABORT;
|
||||
@ -164,7 +173,7 @@ SettingsServiceLock.prototype = {
|
||||
},
|
||||
|
||||
set: function set(aName, aValue, aCallback) {
|
||||
if (DEBUG) debug("set: " + aName + " " + aValue);
|
||||
if (VERBOSE) debug("set: " + aName + " " + aValue);
|
||||
if (!this._open) {
|
||||
throw "Settings lock not open";
|
||||
}
|
||||
@ -219,7 +228,7 @@ const SETTINGSSERVICE_CID = Components.ID("{f656f0c0-f776-11e1-a21f-08002
|
||||
|
||||
function SettingsService()
|
||||
{
|
||||
if (DEBUG) debug("settingsService Constructor");
|
||||
if (VERBOSE) debug("settingsService Constructor");
|
||||
}
|
||||
|
||||
SettingsService.prototype = {
|
||||
|
Loading…
Reference in New Issue
Block a user