/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- / /* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ /* 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/. */ 'use strict'; /** * This code exists to be a "grab bag" of global code that needs to be * loaded per B2G process, but doesn't need to directly interact with * web content. * * (It's written as an XPCOM service because it needs to watch * app-startup.) */ const Cc = Components.classes; const Ci = Components.interfaces; const Cu = Components.utils; Cu.import('resource://gre/modules/Services.jsm'); Cu.import('resource://gre/modules/XPCOMUtils.jsm'); XPCOMUtils.defineLazyServiceGetter(this, "settings", "@mozilla.org/settingsService;1", "nsISettingsService"); function debug(msg) { log(msg); } function log(msg) { // This file implements console.log(), so use dump(). //dump('ProcessGlobal: ' + msg + '\n'); } function formatStackFrame(aFrame) { let functionName = aFrame.functionName || ''; return ' at ' + functionName + ' (' + aFrame.filename + ':' + aFrame.lineNumber + ':' + aFrame.columnNumber + ')'; } function ConsoleMessage(aMsg, aLevel) { this.timeStamp = Date.now(); this.msg = aMsg; switch (aLevel) { case 'error': case 'assert': this.logLevel = Ci.nsIConsoleMessage.error; break; case 'warn': this.logLevel = Ci.nsIConsoleMessage.warn; break; case 'log': case 'info': this.logLevel = Ci.nsIConsoleMessage.info; break; default: this.logLevel = Ci.nsIConsoleMessage.debug; break; } } function toggleUnrestrictedDevtools(unrestricted) { Services.prefs.setBoolPref("devtools.debugger.forbid-certified-apps", !unrestricted); Services.prefs.setBoolPref("dom.apps.developer_mode", unrestricted); // TODO: Remove once bug 1125916 is fixed. Services.prefs.setBoolPref("network.disable.ipc.security", unrestricted); Services.prefs.setBoolPref("dom.webcomponents.enabled", unrestricted); let lock = settings.createLock(); lock.set("developer.menu.enabled", unrestricted, null); lock.set("devtools.unrestricted", unrestricted, null); } ConsoleMessage.prototype = { QueryInterface: XPCOMUtils.generateQI([Ci.nsIConsoleMessage]), toString: function() { return this.msg; } }; const gFactoryResetFile = "__post_reset_cmd__"; function ProcessGlobal() {} ProcessGlobal.prototype = { classID: Components.ID('{1a94c87a-5ece-4d11-91e1-d29c29f21b28}'), QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver, Ci.nsISupportsWeakReference]), wipeDir: function(path) { log("wipeDir " + path); let dir = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile); dir.initWithPath(path); if (!dir.exists() || !dir.isDirectory()) { return; } let entries = dir.directoryEntries; while (entries.hasMoreElements()) { let file = entries.getNext().QueryInterface(Ci.nsIFile); log("Deleting " + file.path); try { file.remove(true); } catch(e) {} } }, processCommandsFile: function(text) { log("processCommandsFile " + text); let lines = text.split("\n"); lines.forEach((line) => { log(line); let params = line.split(" "); switch (params[0]) { case "root": log("unrestrict devtools"); toggleUnrestrictedDevtools(true); break; case "wipe": this.wipeDir(params[1]); case "normal": log("restrict devtools"); toggleUnrestrictedDevtools(false); break; } }); }, cleanupAfterFactoryReset: function() { log("cleanupAfterWipe start"); Cu.import("resource://gre/modules/osfile.jsm"); let dir = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile); dir.initWithPath("/persist"); var postResetFile = dir.exists() ? OS.Path.join("/persist", gFactoryResetFile): OS.Path.join("/cache", gFactoryResetFile); let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile); file.initWithPath(postResetFile); if (!file.exists()) { debug("No additional command.") return; } let promise = OS.File.read(postResetFile); promise.then( (array) => { file.remove(false); let decoder = new TextDecoder(); this.processCommandsFile(decoder.decode(array)); }, function onError(error) { debug("Error: " + error); } ); log("cleanupAfterWipe end."); }, observe: function pg_observe(subject, topic, data) { switch (topic) { case 'app-startup': { Services.obs.addObserver(this, 'console-api-log-event', false); let inParent = Cc["@mozilla.org/xre/app-info;1"] .getService(Ci.nsIXULRuntime) .processType == Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT; if (inParent) { Services.ppmm.addMessageListener("getProfD", function(message) { return Services.dirsvc.get("ProfD", Ci.nsIFile).path; }); this.cleanupAfterFactoryReset(); } break; } case 'console-api-log-event': { // Pipe `console` log messages to the nsIConsoleService which // writes them to logcat on Gonk. let message = subject.wrappedJSObject; let args = message.arguments; let stackTrace = ''; if (message.stacktrace && (message.level == 'assert' || message.level == 'error' || message.level == 'trace')) { stackTrace = Array.map(message.stacktrace, formatStackFrame).join('\n'); } else { stackTrace = formatStackFrame(message); } if (stackTrace) { args.push('\n' + stackTrace); } let msg = 'Content JS ' + message.level.toUpperCase() + ': ' + Array.join(args, ' '); Services.console.logMessage(new ConsoleMessage(msg, message.level)); break; } } }, }; this.NSGetFactory = XPCOMUtils.generateNSGetFactory([ProcessGlobal]);