Backed out 2 changesets (bug 1428430) for devtools failure on /builds/worker/workspace/build/src/accessible/base/nsAccessibilityService.cpp:1045 a=backout
authorDorel Luca <dluca@mozilla.com>
Fri, 02 Mar 2018 01:48:52 +0200
changeset 461171 5410375734d6ca8be3ff06acdc1c951d87d644ee
parent 461150 2667f0b010c959940d7a12b4311d54a6abd74ac5
child 461237 efeda1e338d314edf86c92510d1901dcf3ac0668
child 461252 df0e967f8e8fa30a69338008b6ee296bf5e9c545
push id1683
push usersfraser@mozilla.com
push dateThu, 26 Apr 2018 16:43:40 +0000
treeherdermozilla-release@5af6cb21869d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbackout
bugs1428430
milestone60.0a1
backs out7d9813d8cb47e68706be16f61d4abeac32dfc25e
a638660a49fa22780b515fb4770742d39c2105bf
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Backed out 2 changesets (bug 1428430) for devtools failure on /builds/worker/workspace/build/src/accessible/base/nsAccessibilityService.cpp:1045 a=backout Backed out changeset 7d9813d8cb47 (bug 1428430) Backed out changeset a638660a49fa (bug 1428430)
devtools/server/actors/accessibility-parent.js
devtools/server/actors/accessibility.js
devtools/server/actors/moz.build
devtools/server/tests/browser/browser.ini
devtools/server/tests/browser/browser_accessibility_node.js
devtools/server/tests/browser/browser_accessibility_node_events.js
devtools/server/tests/browser/browser_accessibility_simple.js
devtools/server/tests/browser/browser_accessibility_walker.js
devtools/server/tests/browser/head.js
devtools/shared/fronts/accessibility.js
devtools/shared/specs/accessibility.js
deleted file mode 100644
--- a/devtools/server/actors/accessibility-parent.js
+++ /dev/null
@@ -1,232 +0,0 @@
-/* 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";
-
-const { Cc, Ci } = require("chrome");
-const Services = require("Services");
-const PREF_ACCESSIBILITY_FORCE_DISABLED = "accessibility.force_disabled";
-
-/**
- * A helper class that does all the work related to accessibility service
- * lifecycle (initialization, shutdown, consumer changes, etc) in parent
- * parent process. It is not guaranteed that the AccessibilityActor starts in
- * parent process and thus triggering these lifecycle functions directly is
- * extremely unreliable.
- */
-class AccessibilityParent {
-  constructor(mm, prefix) {
-    this._msgName = `debug:${prefix}accessibility`;
-    this.onAccessibilityMessage = this.onAccessibilityMessage.bind(this);
-    this.setMessageManager(mm);
-
-    this.userPref = Services.prefs.getIntPref(PREF_ACCESSIBILITY_FORCE_DISABLED);
-    Services.obs.addObserver(this, "a11y-consumers-changed");
-    Services.prefs.addObserver(PREF_ACCESSIBILITY_FORCE_DISABLED, this);
-
-    if (this.enabled && !this.accService) {
-      // Set a local reference to an accessibility service if accessibility was
-      // started elsewhere to ensure that parent process a11y service does not
-      // get GC'ed away.
-      this.accService = Cc["@mozilla.org/accessibilityService;1"].getService(
-        Ci.nsIAccessibilityService);
-    }
-
-    this.messageManager.sendAsyncMessage(`${this._msgName}:event`, {
-      topic: "initialized",
-      data: {
-        canBeDisabled: this.canBeDisabled,
-        canBeEnabled: this.canBeEnabled
-      }
-    });
-  }
-
-  /**
-   * Set up message manager listener to listen for messages coming from the
-   * AccessibilityActor when it is instantiated in the child process.
-   *
-   * @param {Object} mm
-   *        Message manager that corresponds to the current content tab.
-   */
-  setMessageManager(mm) {
-    if (this.messageManager === mm) {
-      return;
-    }
-
-    if (this.messageManager) {
-      // If the browser was swapped we need to reset the message manager.
-      let oldMM = this.messageManager;
-      oldMM.removeMessageListener(this._msgName, this.onAccessibilityMessage);
-    }
-
-    this.messageManager = mm;
-    if (mm) {
-      mm.addMessageListener(this._msgName, this.onAccessibilityMessage);
-    }
-  }
-
-  /**
-   * Content AccessibilityActor message listener.
-   *
-   * @param  {String} msg
-   *         Name of the action to perform.
-   */
-  onAccessibilityMessage(msg) {
-    let { action } = msg.json;
-    switch (action) {
-      case "enable":
-        this.enable();
-        break;
-
-      case "disable":
-        this.disable();
-        break;
-
-      case "disconnect":
-        this.destroy();
-        break;
-
-      default:
-        break;
-    }
-  }
-
-  observe(subject, topic, data) {
-    if (topic === "a11y-consumers-changed") {
-      // This event is fired when accessibility service consumers change. Since
-      // this observer lives in parent process there are 2 possible consumers of
-      // a11y service: XPCOM and PlatformAPI (e.g. screen readers). We only care
-      // about PlatformAPI consumer changes because when set, we can no longer
-      // disable accessibility service.
-      let { PlatformAPI } = JSON.parse(data);
-      this.messageManager.sendAsyncMessage(`${this._msgName}:event`, {
-        topic: "can-be-disabled-change",
-        data: !PlatformAPI
-      });
-    } else if (!this.disabling && topic === "nsPref:changed" &&
-               data === PREF_ACCESSIBILITY_FORCE_DISABLED) {
-      // PREF_ACCESSIBILITY_FORCE_DISABLED preference change event. When set to
-      // >=1, it means that the user wants to disable accessibility service and
-      // prevent it from starting in the future. Note: we also check
-      // this.disabling state when handling this pref change because this is how
-      // we disable the accessibility inspector itself.
-      this.messageManager.sendAsyncMessage(`${this._msgName}:event`, {
-        topic: "can-be-enabled-change",
-        data: Services.prefs.getIntPref(PREF_ACCESSIBILITY_FORCE_DISABLED) < 1
-      });
-    }
-  }
-
-  /**
-   * A getter that indicates if accessibility service is enabled.
-   *
-   * @return {Boolean}
-   *         True if accessibility service is on.
-   */
-  get enabled() {
-    return Services.appinfo.accessibilityEnabled;
-  }
-
-  /**
-   * A getter that indicates if the accessibility service can be disabled.
-   *
-   * @return {Boolean}
-   *         True if accessibility service can be disabled.
-   */
-  get canBeDisabled() {
-    if (this.enabled) {
-      let a11yService = Cc["@mozilla.org/accessibilityService;1"].getService(
-        Ci.nsIAccessibilityService);
-      let { PlatformAPI } = JSON.parse(a11yService.getConsumers());
-      return !PlatformAPI;
-    }
-
-    return true;
-  }
-
-  /**
-   * A getter that indicates if the accessibility service can be enabled.
-   *
-   * @return {Boolean}
-   *         True if accessibility service can be enabled.
-   */
-  get canBeEnabled() {
-    return Services.prefs.getIntPref(PREF_ACCESSIBILITY_FORCE_DISABLED) < 1;
-  }
-
-  /**
-   * Enable accessibility service (via XPCOM service).
-   */
-  enable() {
-    if (this.enabled || !this.canBeEnabled) {
-      return;
-    }
-
-    this.accService = Cc["@mozilla.org/accessibilityService;1"].getService(
-      Ci.nsIAccessibilityService);
-  }
-
-  /**
-   * Force disable accessibility service. This method removes the reference to
-   * the XPCOM a11y service object and flips the
-   * PREF_ACCESSIBILITY_FORCE_DISABLED preference on and off to shutdown a11y
-   * service.
-   */
-  disable() {
-    if (!this.enabled || !this.canBeDisabled) {
-      return;
-    }
-
-    this.disabling = true;
-    this.accService = null;
-    // Set PREF_ACCESSIBILITY_FORCE_DISABLED to 1 to force disable
-    // accessibility service. This is the only way to guarantee an immediate
-    // accessibility service shutdown in all processes. This also prevents
-    // accessibility service from starting up in the future.
-    Services.prefs.setIntPref(PREF_ACCESSIBILITY_FORCE_DISABLED, 1);
-    // Set PREF_ACCESSIBILITY_FORCE_DISABLED back to previous default or user
-    // set value. This will not start accessibility service until the user
-    // activates it again. It simply ensures that accessibility service can
-    // start again (when value is below 1).
-    Services.prefs.setIntPref(PREF_ACCESSIBILITY_FORCE_DISABLED, this.userPref);
-    delete this.disabling;
-  }
-
-  /**
-   * Destroy thie helper class, remove all listeners and if possible disable
-   * accessibility service in the parent process.
-   */
-  destroy() {
-    Services.obs.removeObserver(this, "a11y-consumers-changed");
-    Services.prefs.removeObserver(PREF_ACCESSIBILITY_FORCE_DISABLED, this);
-    this.setMessageManager(null);
-    this.accService = null;
-  }
-}
-
-/**
- * Setup function that runs in parent process and setups AccessibleActor bits
- * that must always run in parent process.
- *
- * @param  {Object} options.mm
- *         Message manager that corresponds to the current content tab.
- * @param  {String} options.prefix
- *         Unique prefix for message manager messages.
- * @return {Object}
- *         Defines event listeners for when client disconnects or browser gets
- *         swapped.
- */
-function setupParentProcess({ mm, prefix }) {
-  let accessibility = new AccessibilityParent(mm, prefix);
-
-  return {
-    onBrowserSwap: newMM => accessibility.setMessageManager(newMM),
-    onDisconnected: () => {
-      accessibility.destroy();
-      accessibility = null;
-    }
-  };
-}
-
-exports.setupParentProcess = setupParentProcess;
--- a/devtools/server/actors/accessibility.js
+++ b/devtools/server/actors/accessibility.js
@@ -1,37 +1,29 @@
 /* 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";
 
-const { Cc, Ci } = require("chrome");
+const { Cc, Ci, Cu } = require("chrome");
 const DevToolsUtils = require("devtools/shared/DevToolsUtils");
-const { DebuggerServer } = require("devtools/server/main");
 const Services = require("Services");
 const { Actor, ActorClassWithSpec } = require("devtools/shared/protocol");
 const defer = require("devtools/shared/defer");
 const events = require("devtools/shared/event-emitter");
 const {
   accessibleSpec,
   accessibleWalkerSpec,
   accessibilitySpec
 } = require("devtools/shared/specs/accessibility");
 
-const { isXUL } = require("devtools/server/actors/highlighters/utils/markup");
-const { isWindowIncluded } = require("devtools/shared/layout/utils");
-const { CustomHighlighterActor, register } =
-  require("devtools/server/actors/highlighters");
-const PREF_ACCESSIBILITY_FORCE_DISABLED = "accessibility.force_disabled";
-
 const nsIAccessibleEvent = Ci.nsIAccessibleEvent;
 const nsIAccessibleStateChangeEvent = Ci.nsIAccessibleStateChangeEvent;
 const nsIPropertyElement = Ci.nsIPropertyElement;
-const nsIAccessibleRole = Ci.nsIAccessibleRole;
 
 const {
   EVENT_TEXT_CHANGED,
   EVENT_TEXT_INSERTED,
   EVENT_TEXT_REMOVED,
   EVENT_ACCELERATOR_CHANGE,
   EVENT_ACTION_CHANGE,
   EVENT_DEFACTION_CHANGE,
@@ -42,104 +34,27 @@ const {
   EVENT_NAME_CHANGE,
   EVENT_OBJECT_ATTRIBUTE_CHANGED,
   EVENT_REORDER,
   EVENT_STATE_CHANGE,
   EVENT_TEXT_ATTRIBUTE_CHANGED,
   EVENT_VALUE_CHANGE
 } = nsIAccessibleEvent;
 
-// TODO: We do not need this once bug 1422913 is fixed. We also would not need
-// to fire a name change event for an accessible that has an updated subtree and
-// that has its name calculated from the said subtree.
-const NAME_FROM_SUBTREE_RULE_ROLES = new Set([
-  nsIAccessibleRole.ROLE_BUTTONDROPDOWN,
-  nsIAccessibleRole.ROLE_BUTTONDROPDOWNGRID,
-  nsIAccessibleRole.ROLE_BUTTONMENU,
-  nsIAccessibleRole.ROLE_CELL,
-  nsIAccessibleRole.ROLE_CHECKBUTTON,
-  nsIAccessibleRole.ROLE_CHECK_MENU_ITEM,
-  nsIAccessibleRole.ROLE_CHECK_RICH_OPTION,
-  nsIAccessibleRole.ROLE_COLUMN,
-  nsIAccessibleRole.ROLE_COLUMNHEADER,
-  nsIAccessibleRole.ROLE_COMBOBOX_OPTION,
-  nsIAccessibleRole.ROLE_DEFINITION,
-  nsIAccessibleRole.ROLE_GRID_CELL,
-  nsIAccessibleRole.ROLE_HEADING,
-  nsIAccessibleRole.ROLE_HELPBALLOON,
-  nsIAccessibleRole.ROLE_HTML_CONTAINER,
-  nsIAccessibleRole.ROLE_KEY,
-  nsIAccessibleRole.ROLE_LABEL,
-  nsIAccessibleRole.ROLE_LINK,
-  nsIAccessibleRole.ROLE_LISTITEM,
-  nsIAccessibleRole.ROLE_MATHML_IDENTIFIER,
-  nsIAccessibleRole.ROLE_MATHML_NUMBER,
-  nsIAccessibleRole.ROLE_MATHML_OPERATOR,
-  nsIAccessibleRole.ROLE_MATHML_TEXT,
-  nsIAccessibleRole.ROLE_MATHML_STRING_LITERAL,
-  nsIAccessibleRole.ROLE_MATHML_GLYPH,
-  nsIAccessibleRole.ROLE_MENUITEM,
-  nsIAccessibleRole.ROLE_OPTION,
-  nsIAccessibleRole.ROLE_OUTLINEITEM,
-  nsIAccessibleRole.ROLE_PAGETAB,
-  nsIAccessibleRole.ROLE_PARENT_MENUITEM,
-  nsIAccessibleRole.ROLE_PUSHBUTTON,
-  nsIAccessibleRole.ROLE_RADIOBUTTON,
-  nsIAccessibleRole.ROLE_RADIO_MENU_ITEM,
-  nsIAccessibleRole.ROLE_RICH_OPTION,
-  nsIAccessibleRole.ROLE_ROW,
-  nsIAccessibleRole.ROLE_ROWHEADER,
-  nsIAccessibleRole.ROLE_SUMMARY,
-  nsIAccessibleRole.ROLE_SWITCH,
-  nsIAccessibleRole.ROLE_TABLE_COLUMN_HEADER,
-  nsIAccessibleRole.ROLE_TABLE_ROW_HEADER,
-  nsIAccessibleRole.ROLE_TEAR_OFF_MENU_ITEM,
-  nsIAccessibleRole.ROLE_TERM,
-  nsIAccessibleRole.ROLE_TOGGLE_BUTTON,
-  nsIAccessibleRole.ROLE_TOOLTIP
-]);
-
-const IS_OSX = Services.appinfo.OS === "Darwin";
-
-register("AccessibleHighlighter", "accessible");
-register("XULWindowAccessibleHighlighter", "xul-accessible");
-
-/**
- * Helper function that determines if nsIAccessible object is in defunct state.
- *
- * @param  {nsIAccessible}  accessible
- *         object to be tested.
- * @return {Boolean}
- *         True if accessible object is defunct, false otherwise.
- */
-function isDefunct(accessible) {
-  let defunct = false;
-
-  try {
-    let extState = {};
-    accessible.getState({}, extState);
-    // extState.value is a bitmask. We are applying bitwise AND to mask out
-    // irrelevant states.
-    defunct = !!(extState.value & Ci.nsIAccessibleStates.EXT_STATE_DEFUNCT);
-  } catch (e) {
-    defunct = true;
-  }
-
-  return defunct;
-}
+const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
 
 /**
  * Set of actors that expose accessibility tree information to the
  * devtools protocol clients.
  *
  * The |Accessibility| actor is the main entry point. It is used to request
  * an AccessibleWalker actor that caches the tree of Accessible actors.
  *
  * The |AccessibleWalker| actor is used to cache all seen Accessible actors as
- * well as observe all relevant accessible events.
+ * well as observe all relevant accesible events.
  *
  * The |Accessible| actor provides information about a particular accessible
  * object, its properties, , attributes, states, relations, etc.
  */
 
 /**
  * The AccessibleActor provides information about a given accessible object: its
  * role, name, states, etc.
@@ -152,17 +67,28 @@ const AccessibleActor = ActorClassWithSp
 
     /**
      * Indicates if the raw accessible is no longer alive.
      *
      * @return Boolean
      */
     Object.defineProperty(this, "isDefunct", {
       get() {
-        let defunct = isDefunct(this.rawAccessible);
+        let defunct = false;
+
+        try {
+          let extState = {};
+          this.rawAccessible.getState({}, extState);
+          // extState.value is a bitmask. We are applying bitwise AND to mask out
+          // irrelelvant states.
+          defunct = !!(extState.value & Ci.nsIAccessibleStates.EXT_STATE_DEFUNCT);
+        } catch (e) {
+          defunct = true;
+        }
+
         if (defunct) {
           delete this.isDefunct;
           this.isDefunct = true;
           return this.isDefunct;
         }
 
         return defunct;
       },
@@ -234,201 +160,189 @@ const AccessibleActor = ActorClassWithSp
 
   get domNodeType() {
     if (this.isDefunct) {
       return 0;
     }
     return this.rawAccessible.DOMNode ? this.rawAccessible.DOMNode.nodeType : 0;
   },
 
-  get parentAcc() {
-    if (this.isDefunct) {
-      return null;
-    }
-    return this.walker.addRef(this.rawAccessible.parent);
-  },
-
   children() {
     let children = [];
     if (this.isDefunct) {
       return children;
     }
 
     for (let child = this.rawAccessible.firstChild; child; child = child.nextSibling) {
       children.push(this.walker.addRef(child));
     }
     return children;
   },
 
-  get indexInParent() {
+  getIndexInParent() {
     if (this.isDefunct) {
       return -1;
     }
-
-    try {
-      return this.rawAccessible.indexInParent;
-    } catch (e) {
-      // Accessible is dead.
-      return -1;
-    }
+    return this.rawAccessible.indexInParent;
   },
 
-  get actions() {
+  getActions() {
     let actions = [];
     if (this.isDefunct) {
       return actions;
     }
 
     for (let i = 0; i < this.rawAccessible.actionCount; i++) {
       actions.push(this.rawAccessible.getActionDescription(i));
     }
     return actions;
   },
 
-  get states() {
+  getState() {
     if (this.isDefunct) {
       return [];
     }
 
     let state = {};
     let extState = {};
     this.rawAccessible.getState(state, extState);
     return [
       ...this.walker.a11yService.getStringStates(state.value, extState.value)
     ];
   },
 
-  get attributes() {
+  getAttributes() {
     if (this.isDefunct || !this.rawAccessible.attributes) {
       return {};
     }
 
     let attributes = {};
     let attrsEnum = this.rawAccessible.attributes.enumerate();
     while (attrsEnum.hasMoreElements()) {
       let { key, value } = attrsEnum.getNext().QueryInterface(
         nsIPropertyElement);
       attributes[key] = value;
     }
 
     return attributes;
   },
 
-  get bounds() {
-    if (this.isDefunct) {
-      return null;
-    }
-
-    let x = {}, y = {}, w = {}, h = {};
-    try {
-      this.rawAccessible.getBounds(x, y, w, h);
-      x = x.value;
-      y = y.value;
-      w = w.value;
-      h = h.value;
-    } catch (e) {
-      return null;
-    }
-
-    return { x, y, w, h };
-  },
-
   form() {
     return {
       actor: this.actorID,
       role: this.role,
       name: this.name,
       value: this.value,
       description: this.description,
       help: this.help,
       keyboardShortcut: this.keyboardShortcut,
       childCount: this.childCount,
       domNodeType: this.domNodeType,
-      indexInParent: this.indexInParent,
-      states: this.states,
-      actions: this.actions,
-      attributes: this.attributes
+      walker: this.walker.form()
     };
   }
 });
 
 /**
  * The AccessibleWalkerActor stores a cache of AccessibleActors that represent
  * accessible objects in a given document.
  *
  * It is also responsible for implicitely initializing and shutting down
  * accessibility engine by storing a reference to the XPCOM accessibility
  * service.
  */
 const AccessibleWalkerActor = ActorClassWithSpec(accessibleWalkerSpec, {
   initialize(conn, tabActor) {
     Actor.prototype.initialize.call(this, conn);
     this.tabActor = tabActor;
+    this.rootWin = tabActor.window;
+    this.rootDoc = tabActor.window.document;
     this.refMap = new Map();
-    this.setA11yServiceGetter();
-    this.onPick = this.onPick.bind(this);
-    this.onHovered = this.onHovered.bind(this);
-    this.onKey = this.onKey.bind(this);
+    // Accessibility Walker should only be considered ready, when raw accessible
+    // object for root document is fully initialized (e.g. does not have a
+    // 'busy' state)
+    this.readyDeferred = defer();
 
-    this.highlighter = CustomHighlighterActor(this, isXUL(this.rootWin) ?
-      "XULWindowAccessibleHighlighter" : "AccessibleHighlighter");
-  },
-
-  setA11yServiceGetter() {
     DevToolsUtils.defineLazyGetter(this, "a11yService", () => {
       Services.obs.addObserver(this, "accessible-event");
       return Cc["@mozilla.org/accessibilityService;1"].getService(
         Ci.nsIAccessibilityService);
     });
-  },
 
-  get rootWin() {
-    return this.tabActor && this.tabActor.window;
+    this.onLoad = this.onLoad.bind(this);
+    this.onUnload = this.onUnload.bind(this);
+
+    events.on(tabActor, "will-navigate", this.onUnload);
+    events.on(tabActor, "window-ready", this.onLoad);
   },
 
-  get rootDoc() {
-    return this.tabActor && this.tabActor.window.document;
+  onUnload({ window }) {
+    let doc = window.document;
+    let actor = this.getRef(doc);
+
+    // If an accessible actor was never created for document, then there's
+    // nothing to clean up.
+    if (!actor) {
+      return;
+    }
+
+    // Purge document's subtree from accessible actors cache.
+    this.purgeSubtree(this.a11yService.getAccessibleFor(this.doc));
+    // If document is a root document, clear it's reference and cache.
+    if (this.rootDoc === doc) {
+      this.rootDoc = null;
+      this.refMap.clear();
+      this.readyDeferred = defer();
+    }
   },
 
-  reset() {
+  onLoad({ window, isTopLevel }) {
+    if (isTopLevel) {
+      // If root document is dead, unload it and clean up.
+      if (this.rootDoc && !Cu.isDeadWrapper(this.rootDoc) &&
+          this.rootDoc.defaultView) {
+        this.onUnload({ window: this.rootDoc.defaultView });
+      }
+
+      this.rootWin = window;
+      this.rootDoc = window.document;
+    }
+  },
+
+  destroy() {
+    if (this._destroyed) {
+      return;
+    }
+
+    this._destroyed = true;
+
     try {
       Services.obs.removeObserver(this, "accessible-event");
     } catch (e) {
       // Accessible event observer might not have been initialized if a11y
       // service was never used.
     }
 
-    this.cancelPick();
-
     // Clean up accessible actors cache.
     if (this.refMap.size > 0) {
-      try {
-        if (this.rootDoc) {
-          this.purgeSubtree(this.a11yService.getAccessibleFor(this.rootDoc),
-                            this.rootDoc);
-        }
-      } catch (e) {
-        // Accessibility service might be already destroyed.
-      }
+      this.purgeSubtree(this.a11yService.getAccessibleFor(this.rootDoc));
+      this.refMap.clear();
     }
 
-    delete this.a11yService;
-    this.setA11yServiceGetter();
-  },
-
-  destroy() {
-    Actor.prototype.destroy.call(this);
+    events.off(this.tabActor, "will-navigate", this.onUnload);
+    events.off(this.tabActor, "window-ready", this.onLoad);
 
-    this.reset();
+    this.onLoad = null;
+    this.onUnload = null;
+    delete this.a11yService;
+    this.tabActor = null;
+    this.rootDoc = null;
+    this.refMap = null;
 
-    this.highlighter.destroy();
-    this.highlighter = null;
-
-    this.tabActor = null;
-    this.refMap = null;
+    Actor.prototype.destroy.call(this);
   },
 
   getRef(rawAccessible) {
     return this.refMap.get(rawAccessible);
   },
 
   addRef(rawAccessible) {
     let actor = this.refMap.get(rawAccessible);
@@ -442,37 +356,31 @@ const AccessibleWalkerActor = ActorClass
 
     return actor;
   },
 
   /**
    * Clean up accessible actors cache for a given accessible's subtree.
    *
    * @param  {nsIAccessible} rawAccessible
-   * @param  {null|Object}   rawNode
    */
-  purgeSubtree(rawAccessible, rawNode) {
+  purgeSubtree(rawAccessible) {
     let actor = this.getRef(rawAccessible);
     if (actor && rawAccessible && !actor.isDefunct) {
       for (let child = rawAccessible.firstChild; child; child = child.nextSibling) {
         this.purgeSubtree(child);
       }
     }
 
     this.refMap.delete(rawAccessible);
 
     if (actor) {
       events.emit(this, "accessible-destroy", actor);
       actor.destroy();
     }
-
-    // If corresponding DOMNode is a top level document, clear entire cache.
-    if (rawNode && rawNode === this.rootDoc) {
-      this.refMap.clear();
-    }
   },
 
   /**
    * A helper method. Accessibility walker is assumed to have only 1 child which
    * is the top level document.
    */
   children() {
     return Promise.all([this.getDocument()]);
@@ -480,105 +388,74 @@ const AccessibleWalkerActor = ActorClass
 
   /**
    * A promise for a root document accessible actor that only resolves when its
    * corresponding document accessible object is fully loaded.
    *
    * @return {Promise}
    */
   getDocument() {
-    if (!this.rootDoc || !this.rootDoc.documentElement) {
-      return this.once("document-ready").then(docAcc => this.addRef(docAcc));
-    }
+    let doc = this.addRef(this.a11yService.getAccessibleFor(this.rootDoc));
+    let states = doc.getState();
 
-    if (isXUL(this.rootWin)) {
-      let doc = this.addRef(this.a11yService.getAccessibleFor(this.rootDoc));
-      return Promise.resolve(doc);
+    if (states.includes("busy")) {
+      return this.readyDeferred.promise.then(() => doc);
     }
 
-    let doc = this.a11yService.getAccessibleFor(this.rootDoc);
-    let state = {};
-    doc.getState(state, {});
-    if (state.value & Ci.nsIAccessibleStates.STATE_BUSY) {
-      return this.once("document-ready").then(docAcc => this.addRef(docAcc));
-    }
-
-    return Promise.resolve(this.addRef(doc));
+    this.readyDeferred.resolve();
+    return Promise.resolve(doc);
   },
 
   getAccessibleFor(domNode) {
     // We need to make sure that the document is loaded processed by a11y first.
     return this.getDocument().then(() =>
       this.addRef(this.a11yService.getAccessibleFor(domNode.rawNode)));
   },
 
-  async getAncestry(accessible) {
-    if (accessible.indexInParent === -1) {
-      return [];
-    }
-    const doc = await this.getDocument();
-    let ancestry = [];
-    try {
-      let parent = accessible;
-      while (parent && (parent = parent.parentAcc) && parent != doc) {
-        ancestry.push(parent);
-      }
-      ancestry.push(doc);
-    } catch (error) {
-      throw new Error(`Failed to get ancestor for ${accessible}: ${error}`);
-    }
-
-    return ancestry.map(parent => (
-      { accessible: parent, children: parent.children() }));
-  },
-
   /**
    * Accessible event observer function.
    *
    * @param {nsIAccessibleEvent} subject
    *                                      accessible event object.
    */
   observe(subject) {
     let event = subject.QueryInterface(nsIAccessibleEvent);
     let rawAccessible = event.accessible;
     let accessible = this.getRef(rawAccessible);
 
     switch (event.eventType) {
       case EVENT_STATE_CHANGE:
         let { state, isEnabled } = event.QueryInterface(nsIAccessibleStateChangeEvent);
-        let isBusy = state & Ci.nsIAccessibleStates.STATE_BUSY;
-        // Accessible document is recreated.
-        if (isBusy && !isEnabled && rawAccessible instanceof Ci.nsIAccessibleDocument) {
-          // Remove its existing cache from tree.
-          this.purgeSubtree(rawAccessible, event.DOMNode);
-          // If it's a top level document notify listeners about the document
-          // being ready.
-          if (event.DOMNode == this.rootDoc) {
-            events.emit(this, "document-ready", rawAccessible);
+        let states = [...this.a11yService.getStringStates(state, 0)];
+
+        if (states.includes("busy") && !isEnabled) {
+          let { DOMNode } = event;
+          // If debugging chrome, wait for top level content document loaded,
+          // otherwise wait for root document loaded.
+          if (DOMNode == this.rootDoc || (
+            this.rootDoc.documentElement.namespaceURI === XUL_NS &&
+            this.rootWin.gBrowser.selectedBrowser.contentDocument == DOMNode)) {
+            this.readyDeferred.resolve();
           }
         }
 
         if (accessible) {
           // Only propagate state change events for active accessibles.
-          if (isBusy && isEnabled) {
-            if (rawAccessible instanceof Ci.nsIAccessibleDocument) {
-              // Remove its existing cache from tree.
-              this.purgeSubtree(rawAccessible, event.DOMNode);
-            }
+          if (states.includes("busy") && isEnabled) {
             return;
           }
-          events.emit(accessible, "states-change", accessible.states);
+          events.emit(accessible, "state-change", accessible.getState());
         }
 
         break;
       case EVENT_NAME_CHANGE:
         if (accessible) {
           events.emit(accessible, "name-change", rawAccessible.name,
             event.DOMNode == this.rootDoc ?
-              undefined : this.getRef(rawAccessible.parent), this);
+              undefined : this.getRef(rawAccessible.parent));
         }
         break;
       case EVENT_VALUE_CHANGE:
         if (accessible) {
           events.emit(accessible, "value-change", rawAccessible.value);
         }
         break;
       case EVENT_DESCRIPTION_CHANGE:
@@ -588,565 +465,74 @@ const AccessibleWalkerActor = ActorClass
         break;
       case EVENT_HELP_CHANGE:
         if (accessible) {
           events.emit(accessible, "help-change", rawAccessible.help);
         }
         break;
       case EVENT_REORDER:
         if (accessible) {
-          accessible.children().forEach(child =>
-            events.emit(child, "index-in-parent-change", child.indexInParent));
-          events.emit(accessible, "reorder", rawAccessible.childCount, this);
+          events.emit(accessible, "reorder", rawAccessible.childCount);
         }
         break;
       case EVENT_HIDE:
         this.purgeSubtree(rawAccessible);
         break;
       case EVENT_DEFACTION_CHANGE:
       case EVENT_ACTION_CHANGE:
         if (accessible) {
-          events.emit(accessible, "actions-change", accessible.actions);
+          events.emit(accessible, "actions-change", accessible.getActions());
         }
         break;
       case EVENT_TEXT_CHANGED:
       case EVENT_TEXT_INSERTED:
       case EVENT_TEXT_REMOVED:
         if (accessible) {
-          events.emit(accessible, "text-change", this);
-          if (NAME_FROM_SUBTREE_RULE_ROLES.has(rawAccessible.role)) {
-            events.emit(accessible, "name-change", rawAccessible.name,
-              event.DOMNode == this.rootDoc ?
-                undefined : this.getRef(rawAccessible.parent), this);
-          }
+          events.emit(accessible, "text-change");
         }
         break;
       case EVENT_DOCUMENT_ATTRIBUTES_CHANGED:
       case EVENT_OBJECT_ATTRIBUTE_CHANGED:
       case EVENT_TEXT_ATTRIBUTE_CHANGED:
         if (accessible) {
-          events.emit(accessible, "attributes-change", accessible.attributes);
+          events.emit(accessible, "attributes-change", accessible.getAttributes());
         }
         break;
       case EVENT_ACCELERATOR_CHANGE:
         if (accessible) {
           events.emit(accessible, "shortcut-change", rawAccessible.keyboardShortcut);
         }
         break;
       default:
         break;
     }
-  },
-
-  /**
-   * Public method used to show an accessible object highlighter on the client
-   * side.
-   *
-   * @param  {Object} accessible
-   *         AccessibleActor to be highlighted.
-   * @param  {Object} options
-   *         Object used for passing options. Available options:
-   *         - duration {Number}
-   *                    Duration of time that the highlighter should be shown.
-   * @return {Boolean}
-   *         True if highlighter shows the accessible object.
-   */
-  highlightAccessible(accessible, options = {}) {
-    let bounds = accessible.bounds;
-    if (!bounds) {
-      return false;
-    }
-
-    return this.highlighter.show({ rawNode: accessible.rawAccessible.DOMNode },
-                                 { ...options, ...bounds });
-  },
-
-  /**
-   * Public method used to hide an accessible object highlighter on the client
-   * side.
-   */
-  unhighlight() {
-    this.highlighter.hide();
-  },
-
-  /**
-   * Picking state that indicates if picking is currently enabled and, if so,
-   * what the current and hovered accessible objects are.
-   */
-  _isPicking: false,
-  _currentAccessible: null,
-
-  /**
-   * Check is event handling is allowed.
-   */
-  _isEventAllowed: function ({ view }) {
-    return this.rootWin instanceof Ci.nsIDOMChromeWindow ||
-           isWindowIncluded(this.rootWin, view);
-  },
-
-  _preventContentEvent(event) {
-    event.stopPropagation();
-    event.preventDefault();
-  },
-
-  /**
-   * Click event handler for when picking is enabled.
-   *
-   * @param  {Object} event
-   *         Current click event.
-   */
-  async onPick(event) {
-    if (!this._isPicking) {
-      return;
-    }
-
-    this._preventContentEvent(event);
-    if (!this._isEventAllowed(event)) {
-      return;
-    }
-
-    // If shift is pressed, this is only a preview click, send the event to
-    // the client, but don't stop picking.
-    if (event.shiftKey) {
-      if (!this._currentAccessible) {
-        this._currentAccessible = await this._findAndAttachAccessible(event);
-      }
-      events.emit(this, "picker-accessible-previewed", this._currentAccessible);
-      return;
-    }
-
-    this._stopPickerListeners();
-    this._isPicking = false;
-    if (!this._currentAccessible) {
-      this._currentAccessible = await this._findAndAttachAccessible(event);
-    }
-    events.emit(this, "picker-accessible-picked", this._currentAccessible);
-  },
-
-  /**
-   * Hover event handler for when picking is enabled.
-   *
-   * @param  {Object} event
-   *         Current hover event.
-   */
-  async onHovered(event) {
-    if (!this._isPicking) {
-      return;
-    }
-
-    this._preventContentEvent(event);
-    if (!this._isEventAllowed(event)) {
-      return;
-    }
-
-    let accessible = await this._findAndAttachAccessible(event);
-    if (!accessible) {
-      return;
-    }
-
-    if (this._currentAccessible !== accessible) {
-      let { bounds } = accessible;
-      if (bounds) {
-        this.highlighter.show({ rawNode: event.originalTarget || event.target }, bounds);
-      }
-
-      events.emit(this, "picker-accessible-hovered", accessible);
-      this._currentAccessible = accessible;
-    }
-  },
-
-  /**
-   * Keyboard event handler for when picking is enabled.
-   *
-   * @param  {Object} event
-   *         Current keyboard event.
-   */
-  onKey(event) {
-    if (!this._currentAccessible || !this._isPicking) {
-      return;
-    }
-
-    this._preventContentEvent(event);
-    if (!this._isEventAllowed(event)) {
-      return;
-    }
-
-    /**
-     * KEY: Action/scope
-     * ENTER/CARRIAGE_RETURN: Picks current accessible
-     * ESC/CTRL+SHIFT+C: Cancels picker
-     */
-    switch (event.keyCode) {
-      // Select the element.
-      case event.DOM_VK_RETURN:
-        this._onPick(event);
-        break;
-      // Cancel pick mode.
-      case event.DOM_VK_ESCAPE:
-        this.cancelPick();
-        events.emit(this, "picker-accessible-canceled");
-        break;
-      case event.DOM_VK_C:
-        if ((IS_OSX && event.metaKey && event.altKey) ||
-          (!IS_OSX && event.ctrlKey && event.shiftKey)) {
-          this.cancelPick();
-          events.emit(this, "picker-accessible-canceled");
-        }
-        break;
-      default:
-        break;
-    }
-  },
-
-  /**
-   * Picker method that starts picker content listeners.
-   */
-  pick: function () {
-    if (!this._isPicking) {
-      this._isPicking = true;
-      this._startPickerListeners();
-    }
-  },
-
-  /**
-   * This pick method also focuses the highlighter's target window.
-   */
-  pickAndFocus: function () {
-    this.pick();
-    this.rootWin.focus();
-  },
-
-  /**
-   * Find accessible object that corresponds to a DOMNode and attach (lookup its
-   * ancestry to the root doc) to the AccessibilityWalker tree.
-   *
-   * @param  {Object} event
-   *         Correspoinding content event.
-   * @return {null|Object}
-   *         Accessible object, if available, that corresponds to a DOM node.
-   */
-  async _findAndAttachAccessible(event) {
-    let target = event.originalTarget || event.target;
-    let rawAccessible = this.a11yService.getAccessibleFor(target);
-    // If raw accessible object is defunct or detached, no need to cache it and
-    // its ancestry.
-    if (!rawAccessible || isDefunct(rawAccessible) || rawAccessible.indexInParent < 0) {
-      return {};
-    }
-
-    const doc = await this.getDocument();
-    let accessible = this.addRef(rawAccessible);
-    // There is a chance that ancestry lookup can fail if the accessible is in
-    // the detached subtree. At that point the root accessible object would be
-    // defunct and accessing it via parent property will throw.
-    try {
-      let parent = accessible;
-      while (parent && parent != doc) {
-        parent = parent.parentAcc;
-      }
-    } catch (error) {
-      throw new Error(`Failed to get ancestor for ${accessible}: ${error}`);
-    }
-
-    return accessible;
-  },
-
-  /**
-   * Start picker content listeners.
-   */
-  _startPickerListeners: function () {
-    let target = this.tabActor.chromeEventHandler;
-    target.addEventListener("mousemove", this.onHovered, true);
-    target.addEventListener("click", this.onPick, true);
-    target.addEventListener("mousedown", this._preventContentEvent, true);
-    target.addEventListener("mouseup", this._preventContentEvent, true);
-    target.addEventListener("dblclick", this._preventContentEvent, true);
-    target.addEventListener("keydown", this.onKey, true);
-    target.addEventListener("keyup", this._preventContentEvent, true);
-  },
-
-  /**
-   * If content is still alive, stop picker content listeners.
-   */
-  _stopPickerListeners: function () {
-    let target = this.tabActor.chromeEventHandler;
-
-    if (!target) {
-      return;
-    }
-
-    target.removeEventListener("mousemove", this.onHovered, true);
-    target.removeEventListener("click", this.onPick, true);
-    target.removeEventListener("mousedown", this._preventContentEvent, true);
-    target.removeEventListener("mouseup", this._preventContentEvent, true);
-    target.removeEventListener("dblclick", this._preventContentEvent, true);
-    target.removeEventListener("keydown", this.onKey, true);
-    target.removeEventListener("keyup", this._preventContentEvent, true);
-  },
-
-  /**
-   * Cacncel picker pick. Remvoe all content listeners and hide the highlighter.
-   */
-  cancelPick: function () {
-    this.highlighter.hide();
-
-    if (this._isPicking) {
-      this._stopPickerListeners();
-      this._isPicking = false;
-      this._currentAccessible = null;
-    }
   }
 });
 
 /**
  * The AccessibilityActor is a top level container actor that initializes
  * accessible walker and is the top-most point of interaction for accessibility
  * tools UI.
  */
 const AccessibilityActor = ActorClassWithSpec(accessibilitySpec, {
   initialize(conn, tabActor) {
     Actor.prototype.initialize.call(this, conn);
-
-    this.initializedDeferred = defer();
-
-    if (DebuggerServer.isInChildProcess) {
-      this._msgName = `debug:${this.conn.prefix}accessibility`;
-      this.conn.setupInParent({
-        module: "devtools/server/actors/accessibility-parent",
-        setupParent: "setupParentProcess"
-      });
-
-      this.onMessage = this.onMessage.bind(this);
-      this.messageManager.addMessageListener(`${this._msgName}:event`, this.onMessage);
-    } else {
-      this.userPref = Services.prefs.getIntPref(PREF_ACCESSIBILITY_FORCE_DISABLED);
-      Services.obs.addObserver(this, "a11y-consumers-changed");
-      Services.prefs.addObserver(PREF_ACCESSIBILITY_FORCE_DISABLED, this);
-      this.initializedDeferred.resolve();
-    }
-
-    Services.obs.addObserver(this, "a11y-init-or-shutdown");
     this.tabActor = tabActor;
   },
 
-  bootstrap() {
-    return this.initializedDeferred.promise.then(() => ({
-      enabled: this.enabled,
-      canBeEnabled: this.canBeEnabled,
-      canBeDisabled: this.canBeDisabled
-    }));
-  },
-
-  get enabled() {
-    return Services.appinfo.accessibilityEnabled;
-  },
-
-  get canBeEnabled() {
-    if (DebuggerServer.isInChildProcess) {
-      return this._canBeEnabled;
-    }
-
-    return Services.prefs.getIntPref(PREF_ACCESSIBILITY_FORCE_DISABLED) < 1;
-  },
-
-  get canBeDisabled() {
-    if (DebuggerServer.isInChildProcess) {
-      return this._canBeDisabled;
-    } else if (!this.enabled) {
-      return true;
-    }
-
-    let { PlatformAPI } = JSON.parse(this.walker.a11yService.getConsumers());
-    return !PlatformAPI;
-  },
-
-  /**
-   * Getter for a message manager that corresponds to a current tab. It is onyl
-   * used if the AccessibilityActor runs in the child process.
-   *
-   * @return {Object}
-   *         Message manager that corresponds to the current content tab.
-   */
-  get messageManager() {
-    if (!DebuggerServer.isInChildProcess) {
-      throw new Error(
-        "Message manager should only be used when actor is in child process.");
-    }
-
-    return this.conn.parentMessageManager;
-  },
-
-  onMessage(msg) {
-    let { topic, data } = msg.data;
-
-    switch (topic) {
-      case "initialized":
-        this._canBeEnabled = data.canBeEnabled;
-        this._canBeDisabled = data.canBeDisabled;
-        this.initializedDeferred.resolve();
-        break;
-      case "can-be-disabled-change":
-        this._canBeDisabled = data;
-        events.emit(this, "can-be-disabled-change", this.canBeDisabled);
-        break;
-
-      case "can-be-enabled-change":
-        this._canBeEnabled = data;
-        events.emit(this, "can-be-enabled-change", this.canBeEnabled);
-        break;
-
-      default:
-        break;
-    }
-  },
-
-  /**
-   * Enable acessibility service in the given process.
-   */
-  async enable() {
-    if (this.enabled || !this.canBeEnabled) {
-      return;
-    }
-
-    let initPromise = this.once("init");
-
-    if (DebuggerServer.isInChildProcess) {
-      this.messageManager.sendAsyncMessage(this._msgName, { action: "enable" });
-    } else {
-      // This executes accessibility service lazy getter and adds accessible
-      // events observer.
-      this.walker.a11yService;
-    }
-
-    await initPromise;
-  },
-
-  /**
-   * Disable acessibility service in the given process.
-   */
-  async disable() {
-    if (!this.enabled || !this.canBeDisabled) {
-      return;
-    }
-
-    this.disabling = true;
-    let shutdownPromise = this.once("shutdown");
-    if (DebuggerServer.isInChildProcess) {
-      this.messageManager.sendAsyncMessage(this._msgName, { action: "disable" });
-    } else {
-      // Set PREF_ACCESSIBILITY_FORCE_DISABLED to 1 to force disable
-      // accessibility service. This is the only way to guarantee an immediate
-      // accessibility service shutdown in all processes. This also prevents
-      // accessibility service from starting up in the future.
-      //
-      // TODO: Introduce a shutdown method that is exposed via XPCOM on
-      // accessibility service.
-      Services.prefs.setIntPref(PREF_ACCESSIBILITY_FORCE_DISABLED, 1);
-      // Set PREF_ACCESSIBILITY_FORCE_DISABLED back to previous default or user
-      // set value. This will not start accessibility service until the user
-      // activates it again. It simply ensures that accessibility service can
-      // start again (when value is below 1).
-      Services.prefs.setIntPref(PREF_ACCESSIBILITY_FORCE_DISABLED, this.userPref);
-    }
-
-    await shutdownPromise;
-    delete this.disabling;
-  },
-
-  /**
-   * Observe Accessibility service init and shutdown events. It relays these
-   * events to AccessibilityFront iff the event is fired for the a11y service
-   * that lives in the same process.
-   *
-   * @param  {null} subject
-   *         Not used.
-   * @param  {String} topic
-   *         Name of the a11y service event: "a11y-init-or-shutdown".
-   * @param  {String} data
-   *         "0" corresponds to shutdown and "1" to init.
-   */
-  observe(subject, topic, data) {
-    if (topic === "a11y-init-or-shutdown") {
-      // This event is fired when accessibility service is initialized or shut
-      // down. "init" and "shutdown" events are only relayed when the enabled
-      // state matches the event (e.g. the event came from the same process as
-      // the actor).
-      const enabled = data === "1";
-      if (enabled && this.enabled) {
-        events.emit(this, "init");
-      } else if (!enabled && !this.enabled) {
-        if (this.walker) {
-          this.walker.reset();
-        }
-
-        events.emit(this, "shutdown");
-      }
-    } else if (topic === "a11y-consumers-changed") {
-      // This event is fired when accessibility service consumers change. There
-      // are 3 possible consumers of a11y service: XPCOM, PlatformAPI (e.g.
-      // screen readers) and MainProcess. PlatformAPI consumer can only be set
-      // in parent process, and MainProcess consumer can only be set in child
-      // process. We only care about PlatformAPI consumer changes because when
-      // set, we can no longer disable accessibility service.
-      let { PlatformAPI } = JSON.parse(data);
-      events.emit(this, "can-be-disabled-change", !PlatformAPI);
-    } else if (!this.disabling && topic === "nsPref:changed" &&
-               data === PREF_ACCESSIBILITY_FORCE_DISABLED) {
-      // PREF_ACCESSIBILITY_FORCE_DISABLED preference change event. When set to
-      // >=1, it means that the user wants to disable accessibility service and
-      // prevent it from starting in the future. Note: we also check
-      // this.disabling state when handling this pref change because this is how
-      // we disable the accessibility inspector itself.
-      events.emit(this, "can-be-enabled-change", this.canBeEnabled);
-    }
-  },
-
-  /**
-   * Get or create AccessibilityWalker actor, similar to WalkerActor.
-   *
-   * @return {Object}
-   *         AccessibleWalkerActor for the current tab.
-   */
   getWalker() {
     if (!this.walker) {
       this.walker = new AccessibleWalkerActor(this.conn, this.tabActor);
     }
     return this.walker;
   },
 
-  /**
-   * Destroy accessibility service actor. This method also shutsdown
-   * accessibility service if possible.
-   */
-  async destroy() {
-    if (this.destroyed) {
-      await this.destroyed;
-      return;
-    }
-
-    let resolver;
-    this.destroyed = new Promise(resolve => {
-      resolver = resolve;
-    });
-
-    if (this.walker) {
-      this.walker.reset();
-    }
-
-    Services.obs.removeObserver(this, "a11y-init-or-shutdown");
-    if (DebuggerServer.isInChildProcess) {
-      this.messageManager.removeMessageListener(`${this._msgName}:event`,
-                                                this.onMessage);
-    } else {
-      Services.obs.removeObserver(this, "a11y-consumers-changed");
-      Services.prefs.removeObserver(PREF_ACCESSIBILITY_FORCE_DISABLED, this);
-    }
-
+  destroy() {
     Actor.prototype.destroy.call(this);
+    this.walker.destroy();
     this.walker = null;
     this.tabActor = null;
-    resolver();
   }
 });
 
 exports.AccessibleActor = AccessibleActor;
 exports.AccessibleWalkerActor = AccessibleWalkerActor;
 exports.AccessibilityActor = AccessibilityActor;
--- a/devtools/server/actors/moz.build
+++ b/devtools/server/actors/moz.build
@@ -8,17 +8,16 @@ DIRS += [
     'emulation',
     'highlighters',
     'inspector',
     'utils',
     'webconsole',
 ]
 
 DevToolsModules(
-    'accessibility-parent.js',
     'accessibility.js',
     'actor-registry.js',
     'addon.js',
     'addons.js',
     'animation.js',
     'breakpoint.js',
     'call-watcher.js',
     'canvas.js',
--- a/devtools/server/tests/browser/browser.ini
+++ b/devtools/server/tests/browser/browser.ini
@@ -22,18 +22,18 @@ support-files =
   storage-secured-iframe.html
   stylesheets-nested-iframes.html
   timeline-iframe-child.html
   timeline-iframe-parent.html
   storage-helpers.js
   !/devtools/server/tests/mochitest/hello-actor.js
   !/devtools/client/framework/test/shared-head.js
 
+[browser_accessibility_node_events.js]
 [browser_accessibility_node.js]
-[browser_accessibility_node_events.js]
 [browser_accessibility_simple.js]
 [browser_accessibility_walker.js]
 [browser_animation_emitMutations.js]
 [browser_animation_getFrames.js]
 [browser_animation_getProperties.js]
 [browser_animation_getMultipleStates.js]
 [browser_animation_getPlayers.js]
 [browser_animation_getStateAfterFinished.js]
--- a/devtools/server/tests/browser/browser_accessibility_node.js
+++ b/devtools/server/tests/browser/browser_accessibility_node.js
@@ -5,51 +5,70 @@
 "use strict";
 
 // Checks for the AccessibleActor
 
 add_task(async function () {
   let {client, walker, accessibility} =
     await initAccessibilityFrontForUrl(MAIN_DOMAIN + "doc_accessibility.html");
 
-  let a11yWalker = await accessibility.getWalker();
-  await accessibility.enable();
+  let a11yWalker = await accessibility.getWalker(walker);
   let buttonNode = await walker.querySelector(walker.rootNode, "#button");
   let accessibleFront = await a11yWalker.getAccessibleFor(buttonNode);
 
   checkA11yFront(accessibleFront, {
     name: "Accessible Button",
     role: "pushbutton",
     value: "",
     description: "Accessibility Test",
     help: "",
     keyboardShortcut: "",
     childCount: 1,
-    domNodeType: 1,
-    indexInParent: 1,
-    states: ["focusable", "selectable text", "opaque", "enabled", "sensitive"],
-    actions: [ "Press" ],
-    attributes: {
-      "margin-top": "0px",
-      display: "inline-block",
-      "text-align": "center",
-      "text-indent": "0px",
-      "margin-left": "0px",
-      tag: "button",
-      "margin-right": "0px",
-      id: "button",
-      "margin-bottom": "0px"
-    }
+    domNodeType: 1
   });
 
+  info("Actions");
+  let actions = await accessibleFront.getActions();
+  is(actions.length, 1, "Accessible Front has correct number of actions");
+  is(actions[0], "Press", "Accessible Front default action is correct");
+
+  info("Index in parent");
+  let index = await accessibleFront.getIndexInParent();
+  is(index, 1, "Accessible Front has correct index in parent");
+
+  info("State");
+  let state = await accessibleFront.getState();
+  SimpleTest.isDeeply(state,
+    ["focusable", "selectable text", "opaque", "enabled", "sensitive"],
+    "Accessible Front has correct states");
+
+  info("Attributes");
+  let attributes = await accessibleFront.getAttributes();
+  SimpleTest.isDeeply(attributes, {
+    "margin-top": "0px",
+    display: "inline-block",
+    "text-align": "center",
+    "text-indent": "0px",
+    "margin-left": "0px",
+    tag: "button",
+    "margin-right": "0px",
+    id: "button",
+    "margin-bottom": "0px"
+  }, "Accessible Front has correct attributes");
+
   info("Children");
   let children = await accessibleFront.children();
   is(children.length, 1, "Accessible Front has correct number of children");
   checkA11yFront(children[0], {
     name: "Accessible Button",
     role: "text leaf"
   });
 
-  await accessibility.disable();
-  await waitForA11yShutdown();
+  info("DOM Node");
+  let node = await accessibleFront.getDOMNode(walker);
+  is(node, buttonNode, "Accessible Front has correct DOM node");
+
+  let a11yShutdown = waitForA11yShutdown();
   await client.close();
+  forceCollections();
+  await a11yShutdown;
   gBrowser.removeCurrentTab();
 });
--- a/devtools/server/tests/browser/browser_accessibility_node_events.js
+++ b/devtools/server/tests/browser/browser_accessibility_node_events.js
@@ -5,49 +5,33 @@
 "use strict";
 
 // Checks for the AccessibleActor events
 
 add_task(async function () {
   let {client, walker, accessibility} =
     await initAccessibilityFrontForUrl(MAIN_DOMAIN + "doc_accessibility.html");
 
-  let a11yWalker = await accessibility.getWalker();
-  await accessibility.enable();
-  let rootNode = await walker.getRootNode();
-  let a11yDoc = await a11yWalker.getAccessibleFor(rootNode);
+  let a11yWalker = await accessibility.getWalker(walker);
+  let a11yDoc = await a11yWalker.getDocument();
   let buttonNode = await walker.querySelector(walker.rootNode, "#button");
   let accessibleFront = await a11yWalker.getAccessibleFor(buttonNode);
   let sliderNode = await walker.querySelector(walker.rootNode, "#slider");
   let accessibleSliderFront = await a11yWalker.getAccessibleFor(sliderNode);
   let browser = gBrowser.selectedBrowser;
 
   checkA11yFront(accessibleFront, {
     name: "Accessible Button",
     role: "pushbutton",
     value: "",
     description: "Accessibility Test",
     help: "",
     keyboardShortcut: "",
     childCount: 1,
-    domNodeType: 1,
-    indexInParent: 1,
-    states: ["focusable", "selectable text", "opaque", "enabled", "sensitive"],
-    actions: [ "Press" ],
-    attributes: {
-      "margin-top": "0px",
-      display: "inline-block",
-      "text-align": "center",
-      "text-indent": "0px",
-      "margin-left": "0px",
-      tag: "button",
-      "margin-right": "0px",
-      id: "button",
-      "margin-bottom": "0px"
-    }
+    domNodeType: 1
   });
 
   info("Name change event");
   await emitA11yEvent(accessibleFront, "name-change",
     (name, parent) => {
       checkA11yFront(accessibleFront, { name: "Renamed" });
       checkA11yFront(parent, { }, a11yDoc);
     }, () => ContentTask.spawn(browser, null, () =>
@@ -56,73 +40,54 @@ add_task(async function () {
 
   info("Description change event");
   await emitA11yEvent(accessibleFront, "description-change",
     () => checkA11yFront(accessibleFront, { description: "" }),
     () => ContentTask.spawn(browser, null, () =>
       content.document.getElementById("button").removeAttribute("aria-describedby")));
 
   info("State change event");
+  let states = await accessibleFront.getState();
   let expectedStates = ["unavailable", "selectable text", "opaque"];
-  await emitA11yEvent(accessibleFront, "states-change",
-    newStates => {
-      checkA11yFront(accessibleFront, { states: expectedStates });
-      SimpleTest.isDeeply(newStates, expectedStates, "States are updated");
-    }, () => ContentTask.spawn(browser, null, () =>
+  SimpleTest.isDeeply(states, ["focusable", "selectable text", "opaque",
+                               "enabled", "sensitive"], "States are correct");
+  await emitA11yEvent(accessibleFront, "state-change",
+    newStates => SimpleTest.isDeeply(newStates, expectedStates,
+                                     "States are updated"),
+    () => ContentTask.spawn(browser, null, () =>
       content.document.getElementById("button").setAttribute("disabled", true)));
+  states = await accessibleFront.getState();
+  SimpleTest.isDeeply(states, expectedStates, "States are updated");
 
   info("Attributes change event");
+  let attrs = await accessibleFront.getAttributes();
+  ok(!attrs.live, "Attribute is not present");
   await emitA11yEvent(accessibleFront, "attributes-change",
-    newAttrs => {
-      checkA11yFront(accessibleFront, { attributes: {
-        "container-live": "polite",
-        display: "inline-block",
-        "event-from-input": "false",
-        "explicit-name": "true",
-        id: "button",
-        live: "polite",
-        "margin-bottom": "0px",
-        "margin-left": "0px",
-        "margin-right": "0px",
-        "margin-top": "0px",
-        tag: "button",
-        "text-align": "center",
-        "text-indent": "0px"
-      }});
-      is(newAttrs.live, "polite", "Attributes are updated");
-    }, () => ContentTask.spawn(browser, null, () =>
+    newAttrs => is(newAttrs.live, "polite", "Attributes are updated"),
+    () => ContentTask.spawn(browser, null, () =>
       content.document.getElementById("button").setAttribute("aria-live", "polite")));
+  attrs = await accessibleFront.getAttributes();
+  is(attrs.live, "polite", "Attributes are updated");
 
   info("Value change event");
   checkA11yFront(accessibleSliderFront, { value: "5" });
   await emitA11yEvent(accessibleSliderFront, "value-change",
     () => checkA11yFront(accessibleSliderFront, { value: "6" }),
     () => ContentTask.spawn(browser, null, () =>
       content.document.getElementById("slider").setAttribute("aria-valuenow", "6")));
 
   info("Reorder event");
   is(accessibleSliderFront.childCount, 1, "Slider has only 1 child");
-  let [firstChild, ] = await accessibleSliderFront.children();
-  is(firstChild.indexInParent, 0, "Slider's first child has correct index in parent");
   await emitA11yEvent(accessibleSliderFront, "reorder",
-    childCount => {
-      is(childCount, 2, "Child count is updated");
-      is(accessibleSliderFront.childCount, 2, "Child count is updated");
-      is(firstChild.indexInParent, 1,
-        "Slider's first child has an updated index in parent");
-    }, () => ContentTask.spawn(browser, null, () => {
-      let doc = content.document;
-      let slider = doc.getElementById("slider");
-      let button = doc.createElement("button");
+    childCount => is(childCount, 2, "Child count is updated"),
+    () => ContentTask.spawn(browser, null, () => {
+      let button = content.document.createElement("button");
       button.innerText = "Slider button";
-      content.document.getElementById("slider").insertBefore(button, slider.firstChild);
+      content.document.getElementById("slider").appendChild(button);
     }));
+  is(accessibleSliderFront.childCount, 2, "Child count is updated");
 
-  await emitA11yEvent(firstChild, "index-in-parent-change", indexInParent =>
-    is(indexInParent, 0, "Slider's first child has an updated index in parent"), () =>
-    ContentTask.spawn(browser, null, () =>
-      content.document.getElementById("slider").firstChild.remove()));
-
-  await accessibility.disable();
-  await waitForA11yShutdown();
+  let a11yShutdown = waitForA11yShutdown();
   await client.close();
+  forceCollections();
+  await a11yShutdown;
   gBrowser.removeCurrentTab();
 });
--- a/devtools/server/tests/browser/browser_accessibility_simple.js
+++ b/devtools/server/tests/browser/browser_accessibility_simple.js
@@ -1,68 +1,21 @@
 /* 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";
 
-const PREF_ACCESSIBILITY_FORCE_DISABLED = "accessibility.force_disabled";
-
-function checkAccessibilityState(accessibility, expected) {
-  let { enabled, canBeDisabled, canBeEnabled } = accessibility;
-  is(enabled, expected.enabled, "Enabled state is correct.");
-  is(canBeDisabled, expected.canBeDisabled, "canBeDisabled state is correct.");
-  is(canBeEnabled, expected.canBeEnabled, "canBeEnabled state is correct.");
-}
-
 // Simple checks for the AccessibilityActor and AccessibleWalkerActor
 
 add_task(async function () {
-  let { walker: domWalker, client, accessibility} = await initAccessibilityFrontForUrl(
+  let {client, accessibility} = await initAccessibilityFrontForUrl(
     "data:text/html;charset=utf-8,<title>test</title><div></div>");
 
   ok(accessibility, "The AccessibilityFront was created");
   ok(accessibility.getWalker, "The getWalker method exists");
 
   let a11yWalker = await accessibility.getWalker();
   ok(a11yWalker, "The AccessibleWalkerFront was returned");
 
-  checkAccessibilityState(accessibility,
-    { enabled: false, canBeDisabled: true, canBeEnabled: true });
-
-  info("Force disable accessibility service: updates canBeEnabled flag");
-  let onEvent = accessibility.once("can-be-enabled-change");
-  Services.prefs.setIntPref(PREF_ACCESSIBILITY_FORCE_DISABLED, 1);
-  await onEvent;
-  checkAccessibilityState(accessibility,
-    { enabled: false, canBeDisabled: true, canBeEnabled: false });
-
-  info("Clear force disable accessibility service: updates canBeEnabled flag");
-  onEvent = accessibility.once("can-be-enabled-change");
-  Services.prefs.clearUserPref(PREF_ACCESSIBILITY_FORCE_DISABLED);
-  await onEvent;
-  checkAccessibilityState(accessibility,
-    { enabled: false, canBeDisabled: true, canBeEnabled: true });
-
-  info("Initialize accessibility service");
-  let initEvent = accessibility.once("init");
-  await accessibility.enable();
-  await waitForA11yInit();
-  await initEvent;
-  checkAccessibilityState(accessibility,
-    { enabled: true, canBeDisabled: true, canBeEnabled: true });
-
-  a11yWalker = await accessibility.getWalker();
-  let rootNode = await domWalker.getRootNode();
-  let a11yDoc = await a11yWalker.getAccessibleFor(rootNode);
-  ok(a11yDoc, "Accessible document actor is created");
-
-  info("Shutdown accessibility service");
-  let shutdownEvent = accessibility.once("shutdown");
-  await accessibility.disable();
-  await waitForA11yShutdown();
-  await shutdownEvent;
-  checkAccessibilityState(accessibility,
-    { enabled: false, canBeDisabled: true, canBeEnabled: true });
-
   await client.close();
   gBrowser.removeCurrentTab();
 });
--- a/devtools/server/tests/browser/browser_accessibility_walker.js
+++ b/devtools/server/tests/browser/browser_accessibility_walker.js
@@ -5,47 +5,36 @@
 "use strict";
 
 // Checks for the AccessibleWalkerActor
 
 add_task(async function () {
   let {client, walker, accessibility} =
     await initAccessibilityFrontForUrl(MAIN_DOMAIN + "doc_accessibility.html");
 
-  let a11yWalker = await accessibility.getWalker();
+  let a11yWalker = await accessibility.getWalker(walker);
   ok(a11yWalker, "The AccessibleWalkerFront was returned");
 
-  await accessibility.enable();
-  let rootNode = await walker.getRootNode();
-  let a11yDoc = await a11yWalker.getAccessibleFor(rootNode);
+  let a11yDoc = await a11yWalker.getDocument();
   ok(a11yDoc, "The AccessibleFront for root doc is created");
 
   let children = await a11yWalker.children();
   is(children.length, 1,
     "AccessibleWalker only has 1 child - root doc accessible");
   is(a11yDoc, children[0],
     "Root accessible must be AccessibleWalker's only child");
 
   let buttonNode = await walker.querySelector(walker.rootNode, "#button");
   let accessibleFront = await a11yWalker.getAccessibleFor(buttonNode);
 
   checkA11yFront(accessibleFront, {
     name: "Accessible Button",
     role: "pushbutton"
   });
 
-  let ancestry = await a11yWalker.getAncestry(accessibleFront);
-  is(ancestry.length, 1, "Button is a direct child of a root document.");
-  is(ancestry[0].accessible, a11yDoc,
-    "Button's only ancestor is a root document");
-  is(ancestry[0].children.length, 3,
-    "Root doc should have correct number of children");
-  ok(ancestry[0].children.includes(accessibleFront),
-    "Button accessible front is in root doc's children");
-
   let browser = gBrowser.selectedBrowser;
 
   // Ensure name-change event is emitted by walker when cached accessible's name
   // gets updated (via DOM manipularion).
   await emitA11yEvent(a11yWalker, "name-change",
     (front, parent) => {
       checkA11yFront(front, { name: "Renamed" }, accessibleFront);
       checkA11yFront(parent, { }, a11yDoc);
@@ -73,60 +62,14 @@ add_task(async function () {
 
   // Ensure destory event is emitted by walker when cached accessible's raw
   // accessible gets destroyed.
   await emitA11yEvent(a11yWalker, "accessible-destroy",
     destroyedFront => checkA11yFront(destroyedFront, { }, accessibleFront),
     () => ContentTask.spawn(browser, null, () =>
       content.document.getElementById("button").remove()));
 
-  let shown = await a11yWalker.highlightAccessible(docChildren[0]);
-  ok(shown, "AccessibleHighlighter highlighted the node");
-
-  shown = await a11yWalker.highlightAccessible(a11yDoc);
-  ok(!shown, "AccessibleHighlighter does not highlight an accessible with no bounds");
-  await a11yWalker.unhighlight();
-
-  info("Checking AccessibleWalker picker functionality");
-  ok(a11yWalker.pick, "AccessibleWalker pick method exists");
-  ok(a11yWalker.pickAndFocus, "AccessibleWalker pickAndFocus method exists");
-  ok(a11yWalker.cancelPick, "AccessibleWalker cancelPick method exists");
-
-  let onPickerEvent = a11yWalker.once("picker-accessible-hovered");
-  await a11yWalker.pick();
-  await BrowserTestUtils.synthesizeMouseAtCenter("#h1", { type: "mousemove" }, browser);
-  let acc = await onPickerEvent;
-  checkA11yFront(acc, { name: "Accessibility Test" }, docChildren[0]);
-
-  onPickerEvent = a11yWalker.once("picker-accessible-previewed");
-  await BrowserTestUtils.synthesizeMouseAtCenter("#h1", { shiftKey: true }, browser);
-  acc = await onPickerEvent;
-  checkA11yFront(acc, { name: "Accessibility Test" }, docChildren[0]);
-
-  onPickerEvent = a11yWalker.once("picker-accessible-canceled");
-  await BrowserTestUtils.synthesizeKey("VK_ESCAPE", { type: "keydown" }, browser);
-  await onPickerEvent;
-
-  onPickerEvent = a11yWalker.once("picker-accessible-hovered");
-  await a11yWalker.pick();
-  await BrowserTestUtils.synthesizeMouseAtCenter("#h1", { type: "mousemove" }, browser);
-  await onPickerEvent;
-
-  onPickerEvent = a11yWalker.once("picker-accessible-picked");
-  await BrowserTestUtils.synthesizeMouseAtCenter("#h1", { }, browser);
-  acc = await onPickerEvent;
-  checkA11yFront(acc, { name: "Accessibility Test" }, docChildren[0]);
-
-  await a11yWalker.cancelPick();
-
-  info("Checking document-ready event fired by walker when top level accessible " +
-       "document is recreated.");
-  let reloaded = BrowserTestUtils.browserLoaded(browser);
-  let documentReady = a11yWalker.once("document-ready");
-  browser.reload();
-  await reloaded;
-  await documentReady;
-
-  await accessibility.disable();
-  await waitForA11yShutdown();
+  let a11yShutdown = waitForA11yShutdown();
   await client.close();
+  forceCollections();
+  await a11yShutdown;
   gBrowser.removeCurrentTab();
 });
--- a/devtools/server/tests/browser/head.js
+++ b/devtools/server/tests/browser/head.js
@@ -84,18 +84,16 @@ async function initAccessibilityFrontFor
 
   initDebuggerServer();
   let client = new DebuggerClient(DebuggerServer.connectPipe());
   let form = await connectDebuggerClient(client);
   let inspector = InspectorFront(client, form);
   let walker = await inspector.getWalker();
   let accessibility = AccessibilityFront(client, form);
 
-  await accessibility.bootstrap();
-
   return {inspector, walker, accessibility, client};
 }
 
 function initDebuggerServer() {
   try {
     // Sometimes debugger server does not get destroyed correctly by previous
     // tests.
     DebuggerServer.destroy();
@@ -305,52 +303,29 @@ async function emitA11yEvent(emitter, na
 function checkA11yFront(front, expected, expectedFront) {
   ok(front, "The accessibility front is created");
 
   if (expectedFront) {
     is(front, expectedFront, "Matching accessibility front");
   }
 
   for (let key in expected) {
-    if (["actions", "states", "attributes"].includes(key)) {
-      SimpleTest.isDeeply(front[key], expected[key],
-        `Accessible Front has correct ${key}`);
-    } else {
-      is(front[key], expected[key], `accessibility front has correct ${key}`);
-    }
+    is(front[key], expected[key], `accessibility front has correct ${key}`);
   }
 }
 
-function getA11yInitOrShutdownPromise() {
-  return new Promise(resolve => {
-    let observe = (subject, topic, data) => {
-      Services.obs.removeObserver(observe, "a11y-init-or-shutdown");
-      resolve(data);
-    };
-    Services.obs.addObserver(observe, "a11y-init-or-shutdown");
-  });
-}
-
 /**
  * Wait for accessibility service to shut down. We consider it shut down when
  * an "a11y-init-or-shutdown" event is received with a value of "0".
  */
 async function waitForA11yShutdown() {
-  if (!Services.appinfo.accessibilityEnabled) {
-    return;
-  }
-
-  await getA11yInitOrShutdownPromise().then(data =>
-    data === "0" ? Promise.resolve() : Promise.reject());
-}
+  await ContentTask.spawn(gBrowser.selectedBrowser, {}, () =>
+    new Promise(resolve => {
+      let observe = (subject, topic, data) => {
+        Services.obs.removeObserver(observe, "a11y-init-or-shutdown");
 
-/**
- * Wait for accessibility service to initialize. We consider it initialized when
- * an "a11y-init-or-shutdown" event is received with a value of "1".
- */
-async function waitForA11yInit() {
-  if (Services.appinfo.accessibilityEnabled) {
-    return;
-  }
-
-  await getA11yInitOrShutdownPromise().then(data =>
-    data === "1" ? Promise.resolve() : Promise.reject());
+        if (data === "0") {
+          resolve();
+        }
+      };
+      Services.obs.addObserver(observe, "a11y-init-or-shutdown");
+    }));
 }
--- a/devtools/shared/fronts/accessibility.js
+++ b/devtools/shared/fronts/accessibility.js
@@ -1,99 +1,86 @@
 /* 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";
 
+const DevToolsUtils = require("devtools/shared/DevToolsUtils");
 const {
-  custom,
   Front,
   FrontClassWithSpec,
-  preEvent
+  preEvent,
+  types
 } = require("devtools/shared/protocol.js");
 const {
   accessibleSpec,
   accessibleWalkerSpec,
   accessibilitySpec
 } = require("devtools/shared/specs/accessibility");
+
 const events = require("devtools/shared/event-emitter");
+const ACCESSIBLE_PROPERTIES = [
+  "role",
+  "name",
+  "value",
+  "description",
+  "help",
+  "keyboardShortcut",
+  "childCount",
+  "domNodeType"
+];
 
 const AccessibleFront = FrontClassWithSpec(accessibleSpec, {
   initialize(client, form) {
     Front.prototype.initialize.call(this, client, form);
+
+    // Define getters for accesible properties that are received from the actor.
+    // Note: we would like accessible properties to be iterable for a11y
+    // clients.
+    for (let key of ACCESSIBLE_PROPERTIES) {
+      Object.defineProperty(this, key, {
+        get() {
+          return this._form[key];
+        },
+        enumerable: true
+      });
+    }
   },
 
   marshallPool() {
-    return this.parent();
-  },
-
-  get role() {
-    return this._form.role;
-  },
-
-  get name() {
-    return this._form.name;
-  },
-
-  get value() {
-    return this._form.value;
-  },
-
-  get description() {
-    return this._form.description;
-  },
-
-  get help() {
-    return this._form.help;
-  },
-
-  get keyboardShortcut() {
-    return this._form.keyboardShortcut;
-  },
-
-  get childCount() {
-    return this._form.childCount;
-  },
-
-  get domNodeType() {
-    return this._form.domNodeType;
-  },
-
-  get indexInParent() {
-    return this._form.indexInParent;
-  },
-
-  get states() {
-    return this._form.states;
-  },
-
-  get actions() {
-    return this._form.actions;
-  },
-
-  get attributes() {
-    return this._form.attributes;
+    return this.walker;
   },
 
   form(form, detail) {
     if (detail === "actorid") {
       this.actorID = form;
       return;
     }
 
     this.actorID = form.actor;
     this._form = form;
+    DevToolsUtils.defineLazyGetter(this, "walker", () =>
+      types.getType("accessiblewalker").read(this._form.walker, this));
   },
 
-  nameChange: preEvent("name-change", function (name, parent, walker) {
+  /**
+   * Get a dom node front from accessible actor's raw accessible object's
+   * DONNode property.
+   */
+  getDOMNode(domWalker) {
+    return domWalker.getNodeFromActor(this.actorID,
+                                      ["rawAccessible", "DOMNode"]);
+  },
+
+  nameChange: preEvent("name-change", function (name, parent) {
     this._form.name = name;
     // Name change event affects the tree rendering, we fire this event on
     // accessibility walker as the point of interaction for UI.
-    if (walker) {
-      events.emit(walker, "name-change", this, parent);
+    if (this.walker) {
+      events.emit(this.walker, "name-change", this, parent);
     }
   }),
 
   valueChange: preEvent("value-change", function (value) {
     this._form.value = value;
   }),
 
   descriptionChange: preEvent("description-change", function (description) {
@@ -103,99 +90,47 @@ const AccessibleFront = FrontClassWithSp
   helpChange: preEvent("help-change", function (help) {
     this._form.help = help;
   }),
 
   shortcutChange: preEvent("shortcut-change", function (keyboardShortcut) {
     this._form.keyboardShortcut = keyboardShortcut;
   }),
 
-  reorder: preEvent("reorder", function (childCount, walker) {
+  reorder: preEvent("reorder", function (childCount) {
     this._form.childCount = childCount;
     // Reorder event affects the tree rendering, we fire this event on
     // accessibility walker as the point of interaction for UI.
-    if (walker) {
-      events.emit(walker, "reorder", this);
+    if (this.walker) {
+      events.emit(this.walker, "reorder", this);
     }
   }),
 
-  textChange: preEvent("text-change", function (walker) {
+  textChange: preEvent("text-change", function () {
     // Text event affects the tree rendering, we fire this event on
     // accessibility walker as the point of interaction for UI.
-    if (walker) {
-      events.emit(walker, "text-change", this);
+    if (this.walker) {
+      events.emit(this.walker, "text-change", this);
     }
-  }),
-
-  indexInParentChange: preEvent("index-in-parent-change", function (indexInParent) {
-    this._form.indexInParent = indexInParent;
-  }),
-
-  statesChange: preEvent("states-change", function (states) {
-    this._form.states = states;
-  }),
-
-  actionsChange: preEvent("actions-change", function (actions) {
-    this._form.actions = actions;
-  }),
-
-  attributesChange: preEvent("attributes-change", function (attributes) {
-    this._form.attributes = attributes;
   })
 });
 
 const AccessibleWalkerFront = FrontClassWithSpec(accessibleWalkerSpec, {
   accessibleDestroy: preEvent("accessible-destroy", function (accessible) {
     accessible.destroy();
   }),
 
   form(json) {
     this.actorID = json.actor;
-  },
-
-  pick: custom(function (doFocus) {
-    if (doFocus) {
-      return this.pickAndFocus();
-    }
-
-    return this._pick();
-  }, {
-    impl: "_pick"
-  })
+  }
 });
 
 const AccessibilityFront = FrontClassWithSpec(accessibilitySpec, {
   initialize(client, form) {
     Front.prototype.initialize.call(this, client, form);
     this.actorID = form.accessibilityActor;
     this.manage(this);
-  },
-
-  bootstrap: custom(function () {
-    return this._bootstrap().then(state => {
-      this.enabled = state.enabled;
-      this.canBeEnabled = state.canBeEnabled;
-      this.canBeDisabled = state.canBeDisabled;
-    });
-  }, {
-    impl: "_bootstrap"
-  }),
-
-  init: preEvent("init", function () {
-    this.enabled = true;
-  }),
-
-  shutdown: preEvent("shutdown", function () {
-    this.enabled = false;
-  }),
-
-  canBeEnabled: preEvent("can-be-enabled-change", function (canBeEnabled) {
-    this.canBeEnabled = canBeEnabled;
-  }),
-
-  canBeDisabled: preEvent("can-be-disabled-change", function (canBeDisabled) {
-    this.canBeDisabled = canBeDisabled;
-  })
+  }
 });
 
 exports.AccessibleFront = AccessibleFront;
 exports.AccessibleWalkerFront = AccessibleWalkerFront;
 exports.AccessibilityFront = AccessibilityFront;
--- a/devtools/shared/specs/accessibility.js
+++ b/devtools/shared/specs/accessibility.js
@@ -4,194 +4,136 @@
 
 "use strict";
 
 const protocol = require("devtools/shared/protocol");
 const { Arg, generateActorSpec, RetVal, types } = protocol;
 
 types.addActorType("accessible");
 
-/**
- * Accessible with children listed in the ancestry structure calculated by the
- * walker.
- */
-types.addDictType("accessibleWithChildren", {
-  // Accessible
-  accessible: "accessible",
-  // Accessible's children
-  children: "array:accessible"
-});
-
 const accessibleSpec = generateActorSpec({
   typeName: "accessible",
 
   events: {
     "actions-change": {
       type: "actionsChange",
       actions: Arg(0, "array:string")
     },
     "name-change": {
       type: "nameChange",
       name: Arg(0, "string"),
-      parent: Arg(1, "nullable:accessible"),
-      walker: Arg(2, "nullable:accessiblewalker")
+      parent: Arg(1, "nullable:accessible")
     },
     "value-change": {
       type: "valueChange",
       value: Arg(0, "string")
     },
     "description-change": {
       type: "descriptionChange",
       description: Arg(0, "string")
     },
-    "states-change": {
-      type: "statesChange",
+    "state-change": {
+      type: "stateChange",
       states: Arg(0, "array:string")
     },
     "attributes-change": {
       type: "attributesChange",
-      attributes: Arg(0, "json")
+      states: Arg(0, "json")
     },
     "help-change": {
       type: "helpChange",
       help: Arg(0, "string")
     },
     "shortcut-change": {
       type: "shortcutChange",
       shortcut: Arg(0, "string")
     },
     "reorder": {
       type: "reorder",
-      childCount: Arg(0, "number"),
-      walker: Arg(1, "nullable:accessiblewalker")
+      childCount: Arg(0, "number")
     },
     "text-change": {
-      type: "textChange",
-      walker: Arg(0, "nullable:accessiblewalker")
-    },
-    "index-in-parent-change": {
-      type: "indexInParentChange",
-      indexInParent: Arg(0, "number")
+      type: "textChange"
     }
   },
 
   methods: {
+    getActions: {
+      request: {},
+      response: {
+        actions: RetVal("array:string")
+      }
+    },
+    getIndexInParent: {
+      request: {},
+      response: {
+        indexInParent: RetVal("number")
+      }
+    },
+    getState: {
+      request: {},
+      response: {
+        states: RetVal("array:string")
+      }
+    },
+    getAttributes: {
+      request: {},
+      response: {
+        attributes: RetVal("json")
+      }
+    },
     children: {
       request: {},
       response: {
         children: RetVal("array:accessible")
       }
     }
   }
 });
 
 const accessibleWalkerSpec = generateActorSpec({
   typeName: "accessiblewalker",
 
   events: {
     "accessible-destroy": {
       type: "accessibleDestroy",
       accessible: Arg(0, "accessible")
-    },
-    "document-ready": {
-      type: "documentReady",
-    },
-    "picker-accessible-picked": {
-      type: "pickerAccessiblePicked",
-      accessible: Arg(0, "nullable:accessible")
-    },
-    "picker-accessible-previewed": {
-      type: "pickerAccessiblePreviewed",
-      accessible: Arg(0, "nullable:accessible")
-    },
-    "picker-accessible-hovered": {
-      type: "pickerAccessibleHovered",
-      accessible: Arg(0, "nullable:accessible")
-    },
-    "picker-accessible-canceled": {
-      type: "pickerAccessibleCanceled"
     }
   },
 
   methods: {
     children: {
       request: {},
       response: {
         children: RetVal("array:accessible")
       }
     },
+    getDocument: {
+      request: {},
+      response: {
+        document: RetVal("accessible")
+      }
+    },
     getAccessibleFor: {
       request: { node: Arg(0, "domnode") },
       response: {
         accessible: RetVal("accessible")
       }
-    },
-    getAncestry: {
-      request: { accessible: Arg(0, "accessible") },
-      response: {
-        ancestry: RetVal("array:accessibleWithChildren")
-      }
-    },
-    highlightAccessible: {
-      request: {
-        accessible: Arg(0, "accessible"),
-        options: Arg(1, "nullable:json")
-      },
-      response: {
-        value: RetVal("nullable:boolean")
-      }
-    },
-    unhighlight: {
-      request: {}
-    },
-    pick: {},
-    pickAndFocus: {},
-    cancelPick: {}
+    }
   }
 });
 
 const accessibilitySpec = generateActorSpec({
   typeName: "accessibility",
 
-  events: {
-    "init": {
-      type: "init"
-    },
-    "shutdown": {
-      type: "shutdown"
-    },
-    "can-be-disabled-change": {
-      type: "canBeDisabledChange",
-      canBeDisabled: Arg(0, "boolean")
-    },
-    "can-be-enabled-change": {
-      type: "canBeEnabledChange",
-      canBeEnabled: Arg(0, "boolean")
-    }
-  },
-
   methods: {
-    bootstrap: {
-      request: {},
-      response: {
-        state: RetVal("json")
-      }
-    },
     getWalker: {
       request: {},
       response: {
         walker: RetVal("accessiblewalker")
       }
-    },
-    enable: {
-      request: {},
-      response: {}
-    },
-    disable: {
-      request: {},
-      response: {}
     }
   }
 });
 
 exports.accessibleSpec = accessibleSpec;
 exports.accessibleWalkerSpec = accessibleWalkerSpec;
 exports.accessibilitySpec = accessibilitySpec;