summaryrefslogtreecommitdiffstats
path: root/b2g/chrome/content/devtools/adb.js
diff options
context:
space:
mode:
Diffstat (limited to 'b2g/chrome/content/devtools/adb.js')
-rw-r--r--b2g/chrome/content/devtools/adb.js233
1 files changed, 233 insertions, 0 deletions
diff --git a/b2g/chrome/content/devtools/adb.js b/b2g/chrome/content/devtools/adb.js
new file mode 100644
index 000000000..cebc6696b
--- /dev/null
+++ b/b2g/chrome/content/devtools/adb.js
@@ -0,0 +1,233 @@
+/* -*- 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
+
+Components.utils.import("resource://gre/modules/FileUtils.jsm");
+
+const DEBUG = false;
+var debug = function(str) {
+ dump("AdbController: " + str + "\n");
+}
+
+var AdbController = {
+ locked: undefined,
+ remoteDebuggerEnabled: undefined,
+ lockEnabled: undefined,
+ disableAdbTimer: null,
+ disableAdbTimeoutHours: 12,
+ umsActive: false,
+
+ setLockscreenEnabled: function(value) {
+ this.lockEnabled = value;
+ DEBUG && debug("setLockscreenEnabled = " + this.lockEnabled);
+ this.updateState();
+ },
+
+ setLockscreenState: function(value) {
+ this.locked = value;
+ DEBUG && debug("setLockscreenState = " + this.locked);
+ this.updateState();
+ },
+
+ setRemoteDebuggerState: function(value) {
+ this.remoteDebuggerEnabled = value;
+ DEBUG && 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) {
+ DEBUG && debug("Timer to disable ADB not started due to zero timeout");
+ return;
+ }
+
+ DEBUG && 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() {
+ DEBUG && 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.
+ debug("ADB timer expired - disabling ADB\n");
+ navigator.mozSettings.createLock().set(
+ {'debugger.remote-mode': 'disabled'});
+ }
+ },
+
+ updateState: function() {
+ this.umsActive = false;
+ },
+
+ updateStateInternal: function() {
+ DEBUG && 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.
+ DEBUG && 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;
+ DEBUG && 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").split(",");
+ let usbFuncActive = this.umsActive || isDebugging;
+ usbFuncActive |= (sysUsbConfig.indexOf("rndis") >= 0);
+ usbFuncActive |= (sysUsbConfig.indexOf("mtp") >= 0);
+
+ 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.
+ }
+
+ // Check wakelock to prevent adb from disconnecting when phone is locked
+ let lockFile = Cc['@mozilla.org/file/local;1'].createInstance(Ci.nsIFile);
+ lockFile.initWithPath('/sys/power/wake_lock');
+ if(lockFile.exists()) {
+ let foStream = Cc["@mozilla.org/network/file-input-stream;1"]
+ .createInstance(Ci.nsIFileInputStream);
+ let coStream = Cc["@mozilla.org/intl/converter-input-stream;1"]
+ .createInstance(Ci.nsIConverterInputStream);
+ let str = {};
+ foStream.init(lockFile, FileUtils.MODE_RDONLY, 0, 0);
+ coStream.init(foStream, "UTF-8", 0, 0);
+ coStream.readString(-1, str);
+ coStream.close();
+ foStream.close();
+ let wakeLockContents = str.value.replace(/\n/, "");
+ let wakeLockList = wakeLockContents.split(" ");
+ if (wakeLockList.indexOf("adb") >= 0) {
+ enableAdb = true;
+ useDisableAdbTimer = false;
+ DEBUG && debug("Keeping ADB enabled as ADB wakelock is present.");
+ } else {
+ DEBUG && debug("ADB wakelock not found.");
+ }
+ } else {
+ DEBUG && debug("Wake_lock file not found.");
+ }
+
+ DEBUG && 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(",");
+ if (currentConfig == "" || currentConfig == "none") {
+ // We want to treat none like the empty string.
+ // "".split(",") yields [""] and not []
+ configFuncs = [];
+ }
+ 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 == "") {
+ // Convert the empty string back into none, since that's what init.rc
+ // needs.
+ newConfig = "none";
+ }
+ if (newConfig != currentConfig) {
+ DEBUG && debug("updateState: currentConfig = " + currentConfig);
+ DEBUG && debug("updateState: newConfig = " + newConfig);
+ try {
+ libcutils.property_set("persist.sys.usb.config", newConfig);
+ } catch(e) {
+ Cu.reportError("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));