mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-30 16:22:00 +00:00
Bug 1039493 - Break out B2G DevTools files. r=fabrice
--HG-- rename : b2g/chrome/content/devtools.js => b2g/chrome/content/devtools/hud.js
This commit is contained in:
parent
6788da60da
commit
3bb8e41245
251
b2g/chrome/content/devtools/adb.js
Normal file
251
b2g/chrome/content/devtools/adb.js
Normal file
@ -0,0 +1,251 @@
|
||||
/* -*- 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 file is only loaded on Gonk to manage ADB state
|
||||
|
||||
let AdbController = {
|
||||
DEBUG: false,
|
||||
locked: undefined,
|
||||
remoteDebuggerEnabled: undefined,
|
||||
lockEnabled: undefined,
|
||||
disableAdbTimer: null,
|
||||
disableAdbTimeoutHours: 12,
|
||||
umsActive: false,
|
||||
|
||||
debug: function(str) {
|
||||
dump("AdbController: " + str + "\n");
|
||||
},
|
||||
|
||||
setLockscreenEnabled: function(value) {
|
||||
this.lockEnabled = value;
|
||||
if (this.DEBUG) {
|
||||
this.debug("setLockscreenEnabled = " + this.lockEnabled);
|
||||
}
|
||||
this.updateState();
|
||||
},
|
||||
|
||||
setLockscreenState: function(value) {
|
||||
this.locked = value;
|
||||
if (this.DEBUG) {
|
||||
this.debug("setLockscreenState = " + this.locked);
|
||||
}
|
||||
this.updateState();
|
||||
},
|
||||
|
||||
setRemoteDebuggerState: function(value) {
|
||||
this.remoteDebuggerEnabled = value;
|
||||
if (this.DEBUG) {
|
||||
this.debug("setRemoteDebuggerState = " + this.remoteDebuggerEnabled);
|
||||
}
|
||||
this.updateState();
|
||||
},
|
||||
|
||||
startDisableAdbTimer: function() {
|
||||
if (this.disableAdbTimer) {
|
||||
this.disableAdbTimer.cancel();
|
||||
} else {
|
||||
this.disableAdbTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
|
||||
try {
|
||||
this.disableAdbTimeoutHours =
|
||||
Services.prefs.getIntPref("b2g.adb.timeout-hours");
|
||||
} catch (e) {
|
||||
// This happens if the pref doesn't exist, in which case
|
||||
// disableAdbTimeoutHours will still be set to the default.
|
||||
}
|
||||
}
|
||||
if (this.disableAdbTimeoutHours <= 0) {
|
||||
if (this.DEBUG) {
|
||||
this.debug("Timer to disable ADB not started due to zero timeout");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.DEBUG) {
|
||||
this.debug("Starting timer to disable ADB in " +
|
||||
this.disableAdbTimeoutHours + " hours");
|
||||
}
|
||||
let timeoutMilliseconds = this.disableAdbTimeoutHours * 60 * 60 * 1000;
|
||||
this.disableAdbTimer.initWithCallback(this, timeoutMilliseconds,
|
||||
Ci.nsITimer.TYPE_ONE_SHOT);
|
||||
},
|
||||
|
||||
stopDisableAdbTimer: function() {
|
||||
if (this.DEBUG) {
|
||||
this.debug("Stopping timer to disable ADB");
|
||||
}
|
||||
if (this.disableAdbTimer) {
|
||||
this.disableAdbTimer.cancel();
|
||||
this.disableAdbTimer = null;
|
||||
}
|
||||
},
|
||||
|
||||
notify: function(aTimer) {
|
||||
if (aTimer == this.disableAdbTimer) {
|
||||
this.disableAdbTimer = null;
|
||||
// The following dump will be the last thing that shows up in logcat,
|
||||
// and will at least give the user a clue about why logcat was
|
||||
// disconnected, if the user happens to be using logcat.
|
||||
dump("AdbController: ADB timer expired - disabling ADB\n");
|
||||
navigator.mozSettings.createLock().set(
|
||||
{'debugger.remote-mode': 'disabled'});
|
||||
}
|
||||
},
|
||||
|
||||
updateState: function() {
|
||||
this.umsActive = false;
|
||||
this.storages = navigator.getDeviceStorages('sdcard');
|
||||
this.updateStorageState(0);
|
||||
},
|
||||
|
||||
updateStorageState: function(storageIndex) {
|
||||
if (storageIndex >= this.storages.length) {
|
||||
// We've iterated through all of the storage objects, now we can
|
||||
// really do updateStateInternal.
|
||||
this.updateStateInternal();
|
||||
return;
|
||||
}
|
||||
let storage = this.storages[storageIndex];
|
||||
if (this.DEBUG) {
|
||||
this.debug("Checking availability of storage: '" +
|
||||
storage.storageName);
|
||||
}
|
||||
|
||||
let req = storage.available();
|
||||
req.onsuccess = function(e) {
|
||||
if (this.DEBUG) {
|
||||
this.debug("Storage: '" + storage.storageName + "' is '" +
|
||||
e.target.result);
|
||||
}
|
||||
if (e.target.result == 'shared') {
|
||||
// We've found a storage area that's being shared with the PC.
|
||||
// We can stop looking now.
|
||||
this.umsActive = true;
|
||||
this.updateStateInternal();
|
||||
return;
|
||||
}
|
||||
this.updateStorageState(storageIndex + 1);
|
||||
}.bind(this);
|
||||
req.onerror = function(e) {
|
||||
dump("AdbController: error querying storage availability for '" +
|
||||
this.storages[storageIndex].storageName + "' (ignoring)\n");
|
||||
this.updateStorageState(storageIndex + 1);
|
||||
}.bind(this);
|
||||
},
|
||||
|
||||
updateStateInternal: function() {
|
||||
if (this.DEBUG) {
|
||||
this.debug("updateStateInternal: called");
|
||||
}
|
||||
|
||||
if (this.remoteDebuggerEnabled === undefined ||
|
||||
this.lockEnabled === undefined ||
|
||||
this.locked === undefined) {
|
||||
// Part of initializing the settings database will cause the observers
|
||||
// to trigger. We want to wait until both have been initialized before
|
||||
// we start changing ther adb state. Without this then we can wind up
|
||||
// toggling adb off and back on again (or on and back off again).
|
||||
//
|
||||
// For completeness, one scenario which toggles adb is using the unagi.
|
||||
// The unagi has adb enabled by default (prior to b2g starting). If you
|
||||
// have the phone lock disabled and remote debugging enabled, then we'll
|
||||
// receive an unlock event and an rde event. However at the time we
|
||||
// receive the unlock event we haven't yet received the rde event, so
|
||||
// we turn adb off momentarily, which disconnects a logcat that might
|
||||
// be running. Changing the defaults (in AdbController) just moves the
|
||||
// problem to a different phone, which has adb disabled by default and
|
||||
// we wind up turning on adb for a short period when we shouldn't.
|
||||
//
|
||||
// By waiting until both values are properly initialized, we avoid
|
||||
// turning adb on or off accidentally.
|
||||
if (this.DEBUG) {
|
||||
this.debug("updateState: Waiting for all vars to be initialized");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if we have a remote debugging session going on. If so, we won't
|
||||
// disable adb even if the screen is locked.
|
||||
let isDebugging = USBRemoteDebugger.isDebugging;
|
||||
if (this.DEBUG) {
|
||||
this.debug("isDebugging=" + isDebugging);
|
||||
}
|
||||
|
||||
// If USB Mass Storage, USB tethering, or a debug session is active,
|
||||
// then we don't want to disable adb in an automatic fashion (i.e.
|
||||
// when the screen locks or due to timeout).
|
||||
let sysUsbConfig = libcutils.property_get("sys.usb.config");
|
||||
let rndisActive = (sysUsbConfig.split(",").indexOf("rndis") >= 0);
|
||||
let usbFuncActive = rndisActive || this.umsActive || isDebugging;
|
||||
|
||||
let enableAdb = this.remoteDebuggerEnabled &&
|
||||
(!(this.lockEnabled && this.locked) || usbFuncActive);
|
||||
|
||||
let useDisableAdbTimer = true;
|
||||
try {
|
||||
if (Services.prefs.getBoolPref("marionette.defaultPrefs.enabled")) {
|
||||
// Marionette is enabled. Marionette requires that adb be on (and also
|
||||
// requires that remote debugging be off). The fact that marionette
|
||||
// is enabled also implies that we're doing a non-production build, so
|
||||
// we want adb enabled all of the time.
|
||||
enableAdb = true;
|
||||
useDisableAdbTimer = false;
|
||||
}
|
||||
} catch (e) {
|
||||
// This means that the pref doesn't exist. Which is fine. We just leave
|
||||
// enableAdb alone.
|
||||
}
|
||||
if (this.DEBUG) {
|
||||
this.debug("updateState: enableAdb = " + enableAdb +
|
||||
" remoteDebuggerEnabled = " + this.remoteDebuggerEnabled +
|
||||
" lockEnabled = " + this.lockEnabled +
|
||||
" locked = " + this.locked +
|
||||
" usbFuncActive = " + usbFuncActive);
|
||||
}
|
||||
|
||||
// Configure adb.
|
||||
let currentConfig = libcutils.property_get("persist.sys.usb.config");
|
||||
let configFuncs = currentConfig.split(",");
|
||||
let adbIndex = configFuncs.indexOf("adb");
|
||||
|
||||
if (enableAdb) {
|
||||
// Add adb to the list of functions, if not already present
|
||||
if (adbIndex < 0) {
|
||||
configFuncs.push("adb");
|
||||
}
|
||||
} else {
|
||||
// Remove adb from the list of functions, if present
|
||||
if (adbIndex >= 0) {
|
||||
configFuncs.splice(adbIndex, 1);
|
||||
}
|
||||
}
|
||||
let newConfig = configFuncs.join(",");
|
||||
if (newConfig != currentConfig) {
|
||||
if (this.DEBUG) {
|
||||
this.debug("updateState: currentConfig = " + currentConfig);
|
||||
this.debug("updateState: newConfig = " + newConfig);
|
||||
}
|
||||
try {
|
||||
libcutils.property_set("persist.sys.usb.config", newConfig);
|
||||
} catch(e) {
|
||||
dump("Error configuring adb: " + e);
|
||||
}
|
||||
}
|
||||
if (useDisableAdbTimer) {
|
||||
if (enableAdb && !usbFuncActive) {
|
||||
this.startDisableAdbTimer();
|
||||
} else {
|
||||
this.stopDisableAdbTimer();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
SettingsListener.observe("lockscreen.locked", false,
|
||||
AdbController.setLockscreenState.bind(AdbController));
|
||||
SettingsListener.observe("lockscreen.enabled", false,
|
||||
AdbController.setLockscreenEnabled.bind(AdbController));
|
275
b2g/chrome/content/devtools/debugger.js
Normal file
275
b2g/chrome/content/devtools/debugger.js
Normal file
@ -0,0 +1,275 @@
|
||||
/* -*- 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";
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "DebuggerServer", function() {
|
||||
Cu.import("resource://gre/modules/devtools/dbg-server.jsm");
|
||||
return DebuggerServer;
|
||||
});
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "devtools", function() {
|
||||
const { devtools } =
|
||||
Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
|
||||
return devtools;
|
||||
});
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "discovery", function() {
|
||||
return devtools.require("devtools/toolkit/discovery/discovery");
|
||||
});
|
||||
|
||||
let RemoteDebugger = {
|
||||
_promptDone: false,
|
||||
_promptAnswer: false,
|
||||
_listening: false,
|
||||
|
||||
prompt: function() {
|
||||
this._listen();
|
||||
|
||||
this._promptDone = false;
|
||||
|
||||
shell.sendChromeEvent({
|
||||
"type": "remote-debugger-prompt"
|
||||
});
|
||||
|
||||
while(!this._promptDone) {
|
||||
Services.tm.currentThread.processNextEvent(true);
|
||||
}
|
||||
|
||||
return this._promptAnswer;
|
||||
},
|
||||
|
||||
_listen: function() {
|
||||
if (this._listening) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.handleEvent = this.handleEvent.bind(this);
|
||||
let content = shell.contentBrowser.contentWindow;
|
||||
content.addEventListener("mozContentEvent", this, false, true);
|
||||
this._listening = true;
|
||||
},
|
||||
|
||||
handleEvent: function(event) {
|
||||
let detail = event.detail;
|
||||
if (detail.type !== "remote-debugger-prompt") {
|
||||
return;
|
||||
}
|
||||
this._promptAnswer = detail.value;
|
||||
this._promptDone = true;
|
||||
},
|
||||
|
||||
initServer: function() {
|
||||
if (DebuggerServer.initialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Ask for remote connections.
|
||||
DebuggerServer.init(this.prompt.bind(this));
|
||||
|
||||
// /!\ Be careful when adding a new actor, especially global actors.
|
||||
// Any new global actor will be exposed and returned by the root actor.
|
||||
|
||||
// Add Firefox-specific actors, but prevent tab actors to be loaded in
|
||||
// the parent process, unless we enable certified apps debugging.
|
||||
let restrictPrivileges = Services.prefs.getBoolPref("devtools.debugger.forbid-certified-apps");
|
||||
DebuggerServer.addBrowserActors("navigator:browser", restrictPrivileges);
|
||||
|
||||
/**
|
||||
* Construct a root actor appropriate for use in a server running in B2G.
|
||||
* The returned root actor respects the factories registered with
|
||||
* DebuggerServer.addGlobalActor only if certified apps debugging is on,
|
||||
* otherwise we used an explicit limited list of global actors
|
||||
*
|
||||
* * @param connection DebuggerServerConnection
|
||||
* The conection to the client.
|
||||
*/
|
||||
DebuggerServer.createRootActor = function createRootActor(connection)
|
||||
{
|
||||
let { Promise: promise } = Cu.import("resource://gre/modules/Promise.jsm", {});
|
||||
let parameters = {
|
||||
// We do not expose browser tab actors yet,
|
||||
// but we still have to define tabList.getList(),
|
||||
// otherwise, client won't be able to fetch global actors
|
||||
// from listTabs request!
|
||||
tabList: {
|
||||
getList: function() {
|
||||
return promise.resolve([]);
|
||||
}
|
||||
},
|
||||
// Use an explicit global actor list to prevent exposing
|
||||
// unexpected actors
|
||||
globalActorFactories: restrictPrivileges ? {
|
||||
webappsActor: DebuggerServer.globalActorFactories.webappsActor,
|
||||
deviceActor: DebuggerServer.globalActorFactories.deviceActor,
|
||||
} : DebuggerServer.globalActorFactories
|
||||
};
|
||||
let { RootActor } = devtools.require("devtools/server/actors/root");
|
||||
let root = new RootActor(connection, parameters);
|
||||
root.applicationType = "operating-system";
|
||||
return root;
|
||||
};
|
||||
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
DebuggerServer.on("connectionchange", function() {
|
||||
AdbController.updateState();
|
||||
});
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
let USBRemoteDebugger = {
|
||||
|
||||
get isDebugging() {
|
||||
if (!this._listener) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return DebuggerServer._connections &&
|
||||
Object.keys(DebuggerServer._connections).length > 0;
|
||||
},
|
||||
|
||||
start: function() {
|
||||
if (this._listener) {
|
||||
return;
|
||||
}
|
||||
|
||||
RemoteDebugger.initServer();
|
||||
|
||||
let portOrPath =
|
||||
Services.prefs.getCharPref("devtools.debugger.unix-domain-socket") ||
|
||||
"/data/local/debugger-socket";
|
||||
|
||||
try {
|
||||
debug("Starting USB debugger on " + portOrPath);
|
||||
this._listener = DebuggerServer.openListener(portOrPath);
|
||||
// Temporary event, until bug 942756 lands and offers a way to know
|
||||
// when the server is up and running.
|
||||
Services.obs.notifyObservers(null, "debugger-server-started", null);
|
||||
} catch (e) {
|
||||
debug("Unable to start USB debugger server: " + e);
|
||||
}
|
||||
},
|
||||
|
||||
stop: function() {
|
||||
if (!this._listener) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
this._listener.close();
|
||||
this._listener = null;
|
||||
} catch (e) {
|
||||
debug("Unable to stop USB debugger server: " + e);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
let WiFiRemoteDebugger = {
|
||||
|
||||
start: function() {
|
||||
if (this._listener) {
|
||||
return;
|
||||
}
|
||||
|
||||
RemoteDebugger.initServer();
|
||||
|
||||
try {
|
||||
debug("Starting WiFi debugger");
|
||||
this._listener = DebuggerServer.openListener(-1);
|
||||
let port = this._listener.port;
|
||||
debug("Started WiFi debugger on " + port);
|
||||
discovery.addService("devtools", { port: port });
|
||||
} catch (e) {
|
||||
debug("Unable to start WiFi debugger server: " + e);
|
||||
}
|
||||
},
|
||||
|
||||
stop: function() {
|
||||
if (!this._listener) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
discovery.removeService("devtools");
|
||||
this._listener.close();
|
||||
this._listener = null;
|
||||
} catch (e) {
|
||||
debug("Unable to stop WiFi debugger server: " + e);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
(function() {
|
||||
// Track these separately here so we can determine the correct value for the
|
||||
// pref "devtools.debugger.remote-enabled", which is true when either mode of
|
||||
// using DevTools is enabled.
|
||||
let devtoolsUSB = false;
|
||||
let devtoolsWiFi = false;
|
||||
|
||||
// Keep the old setting to not break people that won't have updated
|
||||
// gaia and gecko.
|
||||
SettingsListener.observe("devtools.debugger.remote-enabled", false,
|
||||
function(value) {
|
||||
devtoolsUSB = value;
|
||||
Services.prefs.setBoolPref("devtools.debugger.remote-enabled",
|
||||
devtoolsUSB || devtoolsWiFi);
|
||||
// This preference is consulted during startup
|
||||
Services.prefs.savePrefFile(null);
|
||||
try {
|
||||
value ? USBRemoteDebugger.start() : USBRemoteDebugger.stop();
|
||||
} catch(e) {
|
||||
dump("Error while initializing USB devtools: " +
|
||||
e + "\n" + e.stack + "\n");
|
||||
}
|
||||
});
|
||||
|
||||
SettingsListener.observe("debugger.remote-mode", "disabled", function(value) {
|
||||
if (["disabled", "adb-only", "adb-devtools"].indexOf(value) == -1) {
|
||||
dump("Illegal value for debugger.remote-mode: " + value + "\n");
|
||||
return;
|
||||
}
|
||||
|
||||
devtoolsUSB = value == "adb-devtools";
|
||||
Services.prefs.setBoolPref("devtools.debugger.remote-enabled",
|
||||
devtoolsUSB || devtoolsWiFi);
|
||||
// This preference is consulted during startup
|
||||
Services.prefs.savePrefFile(null);
|
||||
|
||||
try {
|
||||
(value == "adb-devtools") ? USBRemoteDebugger.start()
|
||||
: USBRemoteDebugger.stop();
|
||||
} catch(e) {
|
||||
dump("Error while initializing USB devtools: " +
|
||||
e + "\n" + e.stack + "\n");
|
||||
}
|
||||
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
AdbController.setRemoteDebuggerState(value != "disabled");
|
||||
#endif
|
||||
});
|
||||
|
||||
SettingsListener.observe("devtools.remote.wifi.enabled", false,
|
||||
function(value) {
|
||||
devtoolsWiFi = value;
|
||||
Services.prefs.setBoolPref("devtools.debugger.remote-enabled",
|
||||
devtoolsUSB || devtoolsWiFi);
|
||||
// Allow remote debugging on non-local interfaces when WiFi debug is enabled
|
||||
// TODO: Bug 1034411: Lock down to WiFi interface, instead of all interfaces
|
||||
Services.prefs.setBoolPref("devtools.debugger.force-local", !value);
|
||||
// This preference is consulted during startup
|
||||
Services.prefs.savePrefFile(null);
|
||||
|
||||
try {
|
||||
value ? WiFiRemoteDebugger.start() : WiFiRemoteDebugger.stop();
|
||||
} catch(e) {
|
||||
dump("Error while initializing WiFi devtools: " +
|
||||
e + "\n" + e.stack + "\n");
|
||||
}
|
||||
});
|
||||
})();
|
@ -4,6 +4,8 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
// settings.js loads this file when the HUD setting is enabled.
|
||||
|
||||
const DEVELOPER_HUD_LOG_PREFIX = 'DeveloperHUD';
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, 'devtools', function() {
|
@ -4,7 +4,7 @@
|
||||
* 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;"
|
||||
"use strict";
|
||||
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
@ -176,14 +176,14 @@ Components.utils.import('resource://gre/modules/ctypes.jsm');
|
||||
}
|
||||
})();
|
||||
|
||||
// =================== DevTools ====================
|
||||
// =================== DevTools HUD ====================
|
||||
|
||||
let developerHUD;
|
||||
SettingsListener.observe('devtools.overlay', false, (value) => {
|
||||
if (value) {
|
||||
if (!developerHUD) {
|
||||
let scope = {};
|
||||
Services.scriptloader.loadSubScript('chrome://b2g/content/devtools.js', scope);
|
||||
Services.scriptloader.loadSubScript('chrome://b2g/content/devtools/hud.js', scope);
|
||||
developerHUD = scope.developerHUD;
|
||||
}
|
||||
developerHUD.init();
|
||||
@ -194,321 +194,6 @@ SettingsListener.observe('devtools.overlay', false, (value) => {
|
||||
}
|
||||
});
|
||||
|
||||
// =================== Debugger / ADB ====================
|
||||
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
let AdbController = {
|
||||
DEBUG: false,
|
||||
locked: undefined,
|
||||
remoteDebuggerEnabled: undefined,
|
||||
lockEnabled: undefined,
|
||||
disableAdbTimer: null,
|
||||
disableAdbTimeoutHours: 12,
|
||||
umsActive: false,
|
||||
|
||||
debug: function(str) {
|
||||
dump("AdbController: " + str + "\n");
|
||||
},
|
||||
|
||||
setLockscreenEnabled: function(value) {
|
||||
this.lockEnabled = value;
|
||||
if (this.DEBUG) {
|
||||
this.debug("setLockscreenEnabled = " + this.lockEnabled);
|
||||
}
|
||||
this.updateState();
|
||||
},
|
||||
|
||||
setLockscreenState: function(value) {
|
||||
this.locked = value;
|
||||
if (this.DEBUG) {
|
||||
this.debug("setLockscreenState = " + this.locked);
|
||||
}
|
||||
this.updateState();
|
||||
},
|
||||
|
||||
setRemoteDebuggerState: function(value) {
|
||||
this.remoteDebuggerEnabled = value;
|
||||
if (this.DEBUG) {
|
||||
this.debug("setRemoteDebuggerState = " + this.remoteDebuggerEnabled);
|
||||
}
|
||||
this.updateState();
|
||||
},
|
||||
|
||||
startDisableAdbTimer: function() {
|
||||
if (this.disableAdbTimer) {
|
||||
this.disableAdbTimer.cancel();
|
||||
} else {
|
||||
this.disableAdbTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
|
||||
try {
|
||||
this.disableAdbTimeoutHours =
|
||||
Services.prefs.getIntPref("b2g.adb.timeout-hours");
|
||||
} catch (e) {
|
||||
// This happens if the pref doesn't exist, in which case
|
||||
// disableAdbTimeoutHours will still be set to the default.
|
||||
}
|
||||
}
|
||||
if (this.disableAdbTimeoutHours <= 0) {
|
||||
if (this.DEBUG) {
|
||||
this.debug("Timer to disable ADB not started due to zero timeout");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.DEBUG) {
|
||||
this.debug("Starting timer to disable ADB in " +
|
||||
this.disableAdbTimeoutHours + " hours");
|
||||
}
|
||||
let timeoutMilliseconds = this.disableAdbTimeoutHours * 60 * 60 * 1000;
|
||||
this.disableAdbTimer.initWithCallback(this, timeoutMilliseconds,
|
||||
Ci.nsITimer.TYPE_ONE_SHOT);
|
||||
},
|
||||
|
||||
stopDisableAdbTimer: function() {
|
||||
if (this.DEBUG) {
|
||||
this.debug("Stopping timer to disable ADB");
|
||||
}
|
||||
if (this.disableAdbTimer) {
|
||||
this.disableAdbTimer.cancel();
|
||||
this.disableAdbTimer = null;
|
||||
}
|
||||
},
|
||||
|
||||
notify: function(aTimer) {
|
||||
if (aTimer == this.disableAdbTimer) {
|
||||
this.disableAdbTimer = null;
|
||||
// The following dump will be the last thing that shows up in logcat,
|
||||
// and will at least give the user a clue about why logcat was
|
||||
// disconnected, if the user happens to be using logcat.
|
||||
dump("AdbController: ADB timer expired - disabling ADB\n");
|
||||
navigator.mozSettings.createLock().set(
|
||||
{'debugger.remote-mode': 'disabled'});
|
||||
}
|
||||
},
|
||||
|
||||
updateState: function() {
|
||||
this.umsActive = false;
|
||||
this.storages = navigator.getDeviceStorages('sdcard');
|
||||
this.updateStorageState(0);
|
||||
},
|
||||
|
||||
updateStorageState: function(storageIndex) {
|
||||
if (storageIndex >= this.storages.length) {
|
||||
// We've iterated through all of the storage objects, now we can
|
||||
// really do updateStateInternal.
|
||||
this.updateStateInternal();
|
||||
return;
|
||||
}
|
||||
let storage = this.storages[storageIndex];
|
||||
if (this.DEBUG) {
|
||||
this.debug("Checking availability of storage: '" +
|
||||
storage.storageName);
|
||||
}
|
||||
|
||||
let req = storage.available();
|
||||
req.onsuccess = function(e) {
|
||||
if (this.DEBUG) {
|
||||
this.debug("Storage: '" + storage.storageName + "' is '" +
|
||||
e.target.result);
|
||||
}
|
||||
if (e.target.result == 'shared') {
|
||||
// We've found a storage area that's being shared with the PC.
|
||||
// We can stop looking now.
|
||||
this.umsActive = true;
|
||||
this.updateStateInternal();
|
||||
return;
|
||||
}
|
||||
this.updateStorageState(storageIndex + 1);
|
||||
}.bind(this);
|
||||
req.onerror = function(e) {
|
||||
dump("AdbController: error querying storage availability for '" +
|
||||
this.storages[storageIndex].storageName + "' (ignoring)\n");
|
||||
this.updateStorageState(storageIndex + 1);
|
||||
}.bind(this);
|
||||
},
|
||||
|
||||
updateStateInternal: function() {
|
||||
if (this.DEBUG) {
|
||||
this.debug("updateStateInternal: called");
|
||||
}
|
||||
|
||||
if (this.remoteDebuggerEnabled === undefined ||
|
||||
this.lockEnabled === undefined ||
|
||||
this.locked === undefined) {
|
||||
// Part of initializing the settings database will cause the observers
|
||||
// to trigger. We want to wait until both have been initialized before
|
||||
// we start changing ther adb state. Without this then we can wind up
|
||||
// toggling adb off and back on again (or on and back off again).
|
||||
//
|
||||
// For completeness, one scenario which toggles adb is using the unagi.
|
||||
// The unagi has adb enabled by default (prior to b2g starting). If you
|
||||
// have the phone lock disabled and remote debugging enabled, then we'll
|
||||
// receive an unlock event and an rde event. However at the time we
|
||||
// receive the unlock event we haven't yet received the rde event, so
|
||||
// we turn adb off momentarily, which disconnects a logcat that might
|
||||
// be running. Changing the defaults (in AdbController) just moves the
|
||||
// problem to a different phone, which has adb disabled by default and
|
||||
// we wind up turning on adb for a short period when we shouldn't.
|
||||
//
|
||||
// By waiting until both values are properly initialized, we avoid
|
||||
// turning adb on or off accidentally.
|
||||
if (this.DEBUG) {
|
||||
this.debug("updateState: Waiting for all vars to be initialized");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if we have a remote debugging session going on. If so, we won't
|
||||
// disable adb even if the screen is locked.
|
||||
let isDebugging = USBRemoteDebugger.isDebugging;
|
||||
if (this.DEBUG) {
|
||||
this.debug("isDebugging=" + isDebugging);
|
||||
}
|
||||
|
||||
// If USB Mass Storage, USB tethering, or a debug session is active,
|
||||
// then we don't want to disable adb in an automatic fashion (i.e.
|
||||
// when the screen locks or due to timeout).
|
||||
let sysUsbConfig = libcutils.property_get("sys.usb.config");
|
||||
let rndisActive = (sysUsbConfig.split(",").indexOf("rndis") >= 0);
|
||||
let usbFuncActive = rndisActive || this.umsActive || isDebugging;
|
||||
|
||||
let enableAdb = this.remoteDebuggerEnabled &&
|
||||
(!(this.lockEnabled && this.locked) || usbFuncActive);
|
||||
|
||||
let useDisableAdbTimer = true;
|
||||
try {
|
||||
if (Services.prefs.getBoolPref("marionette.defaultPrefs.enabled")) {
|
||||
// Marionette is enabled. Marionette requires that adb be on (and also
|
||||
// requires that remote debugging be off). The fact that marionette
|
||||
// is enabled also implies that we're doing a non-production build, so
|
||||
// we want adb enabled all of the time.
|
||||
enableAdb = true;
|
||||
useDisableAdbTimer = false;
|
||||
}
|
||||
} catch (e) {
|
||||
// This means that the pref doesn't exist. Which is fine. We just leave
|
||||
// enableAdb alone.
|
||||
}
|
||||
if (this.DEBUG) {
|
||||
this.debug("updateState: enableAdb = " + enableAdb +
|
||||
" remoteDebuggerEnabled = " + this.remoteDebuggerEnabled +
|
||||
" lockEnabled = " + this.lockEnabled +
|
||||
" locked = " + this.locked +
|
||||
" usbFuncActive = " + usbFuncActive);
|
||||
}
|
||||
|
||||
// Configure adb.
|
||||
let currentConfig = libcutils.property_get("persist.sys.usb.config");
|
||||
let configFuncs = currentConfig.split(",");
|
||||
let adbIndex = configFuncs.indexOf("adb");
|
||||
|
||||
if (enableAdb) {
|
||||
// Add adb to the list of functions, if not already present
|
||||
if (adbIndex < 0) {
|
||||
configFuncs.push("adb");
|
||||
}
|
||||
} else {
|
||||
// Remove adb from the list of functions, if present
|
||||
if (adbIndex >= 0) {
|
||||
configFuncs.splice(adbIndex, 1);
|
||||
}
|
||||
}
|
||||
let newConfig = configFuncs.join(",");
|
||||
if (newConfig != currentConfig) {
|
||||
if (this.DEBUG) {
|
||||
this.debug("updateState: currentConfig = " + currentConfig);
|
||||
this.debug("updateState: newConfig = " + newConfig);
|
||||
}
|
||||
try {
|
||||
libcutils.property_set("persist.sys.usb.config", newConfig);
|
||||
} catch(e) {
|
||||
dump("Error configuring adb: " + e);
|
||||
}
|
||||
}
|
||||
if (useDisableAdbTimer) {
|
||||
if (enableAdb && !usbFuncActive) {
|
||||
this.startDisableAdbTimer();
|
||||
} else {
|
||||
this.stopDisableAdbTimer();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
SettingsListener.observe("lockscreen.locked", false,
|
||||
AdbController.setLockscreenState.bind(AdbController));
|
||||
SettingsListener.observe("lockscreen.enabled", false,
|
||||
AdbController.setLockscreenEnabled.bind(AdbController));
|
||||
#endif
|
||||
|
||||
(function() {
|
||||
// Track these separately here so we can determine the correct value for the
|
||||
// pref "devtools.debugger.remote-enabled", which is true when either mode of
|
||||
// using DevTools is enabled.
|
||||
let devtoolsUSB = false;
|
||||
let devtoolsWiFi = false;
|
||||
|
||||
// Keep the old setting to not break people that won't have updated
|
||||
// gaia and gecko.
|
||||
SettingsListener.observe('devtools.debugger.remote-enabled', false,
|
||||
function(value) {
|
||||
devtoolsUSB = value;
|
||||
Services.prefs.setBoolPref('devtools.debugger.remote-enabled',
|
||||
devtoolsUSB || devtoolsWiFi);
|
||||
// This preference is consulted during startup
|
||||
Services.prefs.savePrefFile(null);
|
||||
try {
|
||||
value ? USBRemoteDebugger.start() : USBRemoteDebugger.stop();
|
||||
} catch(e) {
|
||||
dump("Error while initializing USB devtools: "
|
||||
+ e + "\n" + e.stack + "\n");
|
||||
}
|
||||
});
|
||||
|
||||
SettingsListener.observe('debugger.remote-mode', 'disabled', function(value) {
|
||||
if (['disabled', 'adb-only', 'adb-devtools'].indexOf(value) == -1) {
|
||||
dump('Illegal value for debugger.remote-mode: ' + value + '\n');
|
||||
return;
|
||||
}
|
||||
|
||||
devtoolsUSB = value == 'adb-devtools';
|
||||
Services.prefs.setBoolPref('devtools.debugger.remote-enabled',
|
||||
devtoolsUSB || devtoolsWiFi);
|
||||
// This preference is consulted during startup
|
||||
Services.prefs.savePrefFile(null);
|
||||
|
||||
try {
|
||||
(value == 'adb-devtools') ? USBRemoteDebugger.start()
|
||||
: USBRemoteDebugger.stop();
|
||||
} catch(e) {
|
||||
dump("Error while initializing USB devtools: "
|
||||
+ e + "\n" + e.stack + "\n");
|
||||
}
|
||||
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
AdbController.setRemoteDebuggerState(value != 'disabled');
|
||||
#endif
|
||||
});
|
||||
|
||||
SettingsListener.observe('devtools.remote.wifi.enabled', false,
|
||||
function(value) {
|
||||
devtoolsWiFi = value;
|
||||
Services.prefs.setBoolPref('devtools.debugger.remote-enabled',
|
||||
devtoolsUSB || devtoolsWiFi);
|
||||
// Allow remote debugging on non-local interfaces when WiFi debug is enabled
|
||||
// TODO: Bug 1034411: Lock down to WiFi interface, instead of all interfaces
|
||||
Services.prefs.setBoolPref('devtools.debugger.force-local', !value);
|
||||
// This preference is consulted during startup
|
||||
Services.prefs.savePrefFile(null);
|
||||
|
||||
try {
|
||||
value ? WiFiRemoteDebugger.start() : WiFiRemoteDebugger.stop();
|
||||
} catch(e) {
|
||||
dump("Error while initializing WiFi devtools: "
|
||||
+ e + "\n" + e.stack + "\n");
|
||||
}
|
||||
});
|
||||
})();
|
||||
|
||||
// =================== Device Storage ====================
|
||||
SettingsListener.observe('device.storage.writable.name', 'sdcard', function(value) {
|
||||
if (Services.prefs.getPrefType('device.storage.writable.name') != Ci.nsIPrefBranch.PREF_STRING) {
|
||||
|
@ -32,7 +32,14 @@
|
||||
<!-- this script handles the "runapp" argument for desktop builds -->
|
||||
<script type="application/javascript;version=1.8"
|
||||
src="chrome://b2g/content/runapp.js"> </script>
|
||||
#else
|
||||
<!-- this file is only loaded on Gonk to manage ADB state -->
|
||||
<script type="application/javascript;version=1.8"
|
||||
src="chrome://b2g/content/devtools/adb.js"> </script>
|
||||
#endif
|
||||
<!-- manages DevTools server state -->
|
||||
<script type="application/javascript;version=1.8"
|
||||
src="chrome://b2g/content/devtools/debugger.js"> </script>
|
||||
</head>
|
||||
<body id="container">
|
||||
#ifdef FXOS_SIMULATOR
|
||||
|
@ -51,21 +51,6 @@ XPCOMUtils.defineLazyServiceGetter(Services, 'fm',
|
||||
'@mozilla.org/focus-manager;1',
|
||||
'nsIFocusManager');
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, 'DebuggerServer', function() {
|
||||
Cu.import('resource://gre/modules/devtools/dbg-server.jsm');
|
||||
return DebuggerServer;
|
||||
});
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, 'devtools', function() {
|
||||
const { devtools } =
|
||||
Cu.import('resource://gre/modules/devtools/Loader.jsm', {});
|
||||
return devtools;
|
||||
});
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, 'discovery', function() {
|
||||
return devtools.require('devtools/toolkit/discovery/discovery');
|
||||
});
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "ppmm", function() {
|
||||
return Cc["@mozilla.org/parentprocessmessagemanager;1"]
|
||||
.getService(Ci.nsIMessageListenerManager);
|
||||
@ -730,9 +715,6 @@ var CustomEventManager = {
|
||||
case 'system-message-listener-ready':
|
||||
Services.obs.notifyObservers(null, 'system-message-listener-ready', null);
|
||||
break;
|
||||
case 'remote-debugger-prompt':
|
||||
RemoteDebugger.handleEvent(detail);
|
||||
break;
|
||||
case 'captive-portal-login-cancel':
|
||||
CaptivePortalLoginHelper.handleEvent(detail);
|
||||
break;
|
||||
@ -860,172 +842,6 @@ let IndexedDBPromptHelper = {
|
||||
}
|
||||
}
|
||||
|
||||
let RemoteDebugger = {
|
||||
_promptDone: false,
|
||||
_promptAnswer: false,
|
||||
|
||||
prompt: function debugger_prompt() {
|
||||
this._promptDone = false;
|
||||
|
||||
shell.sendChromeEvent({
|
||||
"type": "remote-debugger-prompt"
|
||||
});
|
||||
|
||||
while(!this._promptDone) {
|
||||
Services.tm.currentThread.processNextEvent(true);
|
||||
}
|
||||
|
||||
return this._promptAnswer;
|
||||
},
|
||||
|
||||
handleEvent: function debugger_handleEvent(detail) {
|
||||
this._promptAnswer = detail.value;
|
||||
this._promptDone = true;
|
||||
},
|
||||
|
||||
initServer: function() {
|
||||
if (DebuggerServer.initialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Ask for remote connections.
|
||||
DebuggerServer.init(this.prompt.bind(this));
|
||||
|
||||
// /!\ Be careful when adding a new actor, especially global actors.
|
||||
// Any new global actor will be exposed and returned by the root actor.
|
||||
|
||||
// Add Firefox-specific actors, but prevent tab actors to be loaded in
|
||||
// the parent process, unless we enable certified apps debugging.
|
||||
let restrictPrivileges = Services.prefs.getBoolPref("devtools.debugger.forbid-certified-apps");
|
||||
DebuggerServer.addBrowserActors("navigator:browser", restrictPrivileges);
|
||||
|
||||
/**
|
||||
* Construct a root actor appropriate for use in a server running in B2G.
|
||||
* The returned root actor respects the factories registered with
|
||||
* DebuggerServer.addGlobalActor only if certified apps debugging is on,
|
||||
* otherwise we used an explicit limited list of global actors
|
||||
*
|
||||
* * @param connection DebuggerServerConnection
|
||||
* The conection to the client.
|
||||
*/
|
||||
DebuggerServer.createRootActor = function createRootActor(connection)
|
||||
{
|
||||
let { Promise: promise } = Cu.import("resource://gre/modules/Promise.jsm", {});
|
||||
let parameters = {
|
||||
// We do not expose browser tab actors yet,
|
||||
// but we still have to define tabList.getList(),
|
||||
// otherwise, client won't be able to fetch global actors
|
||||
// from listTabs request!
|
||||
tabList: {
|
||||
getList: function() {
|
||||
return promise.resolve([]);
|
||||
}
|
||||
},
|
||||
// Use an explicit global actor list to prevent exposing
|
||||
// unexpected actors
|
||||
globalActorFactories: restrictPrivileges ? {
|
||||
webappsActor: DebuggerServer.globalActorFactories.webappsActor,
|
||||
deviceActor: DebuggerServer.globalActorFactories.deviceActor,
|
||||
} : DebuggerServer.globalActorFactories
|
||||
};
|
||||
let { RootActor } = devtools.require("devtools/server/actors/root");
|
||||
let root = new RootActor(connection, parameters);
|
||||
root.applicationType = "operating-system";
|
||||
return root;
|
||||
};
|
||||
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
DebuggerServer.on("connectionchange", function() {
|
||||
AdbController.updateState();
|
||||
});
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
let USBRemoteDebugger = {
|
||||
|
||||
get isDebugging() {
|
||||
if (!this._listener) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return DebuggerServer._connections &&
|
||||
Object.keys(DebuggerServer._connections).length > 0;
|
||||
},
|
||||
|
||||
start: function() {
|
||||
if (this._listener) {
|
||||
return;
|
||||
}
|
||||
|
||||
RemoteDebugger.initServer();
|
||||
|
||||
let portOrPath =
|
||||
Services.prefs.getCharPref("devtools.debugger.unix-domain-socket") ||
|
||||
"/data/local/debugger-socket";
|
||||
|
||||
try {
|
||||
debug("Starting USB debugger on " + portOrPath);
|
||||
this._listener = DebuggerServer.openListener(portOrPath);
|
||||
// Temporary event, until bug 942756 lands and offers a way to know
|
||||
// when the server is up and running.
|
||||
Services.obs.notifyObservers(null, 'debugger-server-started', null);
|
||||
} catch (e) {
|
||||
debug('Unable to start USB debugger server: ' + e);
|
||||
}
|
||||
},
|
||||
|
||||
stop: function() {
|
||||
if (!this._listener) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
this._listener.close();
|
||||
this._listener = null;
|
||||
} catch (e) {
|
||||
debug('Unable to stop USB debugger server: ' + e);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
let WiFiRemoteDebugger = {
|
||||
|
||||
start: function() {
|
||||
if (this._listener) {
|
||||
return;
|
||||
}
|
||||
|
||||
RemoteDebugger.initServer();
|
||||
|
||||
try {
|
||||
debug("Starting WiFi debugger");
|
||||
this._listener = DebuggerServer.openListener(-1);
|
||||
let port = this._listener.port;
|
||||
debug("Started WiFi debugger on " + port);
|
||||
discovery.addService("devtools", { port: port });
|
||||
} catch (e) {
|
||||
debug('Unable to start WiFi debugger server: ' + e);
|
||||
}
|
||||
},
|
||||
|
||||
stop: function() {
|
||||
if (!this._listener) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
discovery.removeService("devtools");
|
||||
this._listener.close();
|
||||
this._listener = null;
|
||||
} catch (e) {
|
||||
debug('Unable to stop WiFi debugger server: ' + e);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
let KeyboardHelper = {
|
||||
handleEvent: function keyboard_handleEvent(detail) {
|
||||
Keyboard.setLayouts(detail.layouts);
|
||||
|
@ -13,7 +13,11 @@ chrome.jar:
|
||||
* content/shell.html (content/shell.html)
|
||||
* content/shell.js (content/shell.js)
|
||||
content/shell.css (content/shell.css)
|
||||
content/devtools.js (content/devtools.js)
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
content/devtools/adb.js (content/devtools/adb.js)
|
||||
#endif
|
||||
* content/devtools/debugger.js (content/devtools/debugger.js)
|
||||
content/devtools/hud.js (content/devtools/hud.js)
|
||||
#ifdef FXOS_SIMULATOR
|
||||
content/desktop.css (content/desktop.css)
|
||||
content/images/desktop/home-black.png (content/images/desktop/home-black.png)
|
||||
|
Loading…
Reference in New Issue
Block a user