Merge the last PGO-green inbound changeset to m-c.
authorRyan VanderMeulen <ryanvm@gmail.com>
Fri, 07 Sep 2012 23:51:19 -0400
changeset 104636 1d4fc0c6006353708924d8a0583ef809db925a70
parent 104598 530da2e30cef5a11233bf73520bdf18f41ed5d74 (current diff)
parent 104635 34b091c8b0c844809eaaf1ecd7a2988ac9ed8b22 (diff)
child 104637 2abc79eb92830241f5b367dd88dfb618978a5cb7
child 104641 928f0bc78bc5dc6694ba1bc17d014a2e1dbfa18f
push id23433
push userryanvm@gmail.com
push dateSat, 08 Sep 2012 04:11:45 +0000
treeherdermozilla-central@1d4fc0c60063 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone18.0a1
first release with
nightly linux32
1d4fc0c60063 / 18.0a1 / 20120908030556 / files
nightly linux64
1d4fc0c60063 / 18.0a1 / 20120908030556 / files
nightly mac
1d4fc0c60063 / 18.0a1 / 20120908030556 / files
nightly win32
1d4fc0c60063 / 18.0a1 / 20120908030556 / files
nightly win64
1d4fc0c60063 / 18.0a1 / 20120908030556 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge the last PGO-green inbound changeset to m-c.
build/mobile/b2gemulator.py
build/mobile/devicemanager-utils.py
build/mobile/devicemanager.py
build/mobile/devicemanagerADB.py
build/mobile/devicemanagerSUT.py
build/mobile/droid.py
build/mobile/emulator.py
build/mobile/emulator_battery.py
dom/base/nsDOMClassInfo.cpp
gfx/gl/GLContextProviderOSMesa.cpp
js/xpconnect/src/xpcprivate.h
testing/mozbase/manifestdestiny/tests/test.py
testing/mozbase/manifestdestiny/tests/test_expressionparser.txt
testing/mozbase/manifestdestiny/tests/test_manifestparser.txt
testing/mozbase/manifestdestiny/tests/test_testmanifest.txt
new file mode 100644
--- /dev/null
+++ b/b2g/gaia/Makefile.in
@@ -0,0 +1,42 @@
+# 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/.
+
+DEPTH     = @DEPTH@
+topsrcdir = @top_srcdir@
+srcdir    = @srcdir@
+VPATH     = @srcdir@
+
+include $(DEPTH)/config/autoconf.mk
+
+GAIA_PATH := gaia/profile
+
+
+# We don't have a wrapper script on Windows yet
+ifneq ($(OS_ARCH),WINNT)
+PROGRAM = $(MOZ_APP_NAME)$(BIN_SUFFIX)
+CSRCS = run-b2g.c
+
+DEFINES += \
+  -DB2G_NAME=\"$(MOZ_APP_NAME)-bin$(BIN_SUFFIX)\" \
+  -DGAIA_PATH=\"$(GAIA_PATH)\" \
+  $(NULL)
+
+# This is needed to avoid making run-b2g depend on mozglue
+WRAP_LDFLAGS :=
+endif
+
+GENERATED_DIRS += $(DIST)/bin/$(GAIA_PATH)
+
+include $(topsrcdir)/config/rules.mk
+
+
+libs::
+	# Below here is how Gaia gets built
+	# The Gaia build system freaks out when N > 1 for -jN
+	$(MAKE) -j1 -C $(GAIADIR) clean
+	$(MAKE) -j1 -C $(GAIADIR) profile GAIA_DOMAIN=desktop-builds.$(MOZ_APP_NAME).mozilla.org
+	(cd $(GAIADIR)/profile && tar $(TAR_CREATE_FLAGS) - .) | (cd $(abspath $(DIST))/bin/$(GAIA_PATH) && tar -xf -)
+
+
+
new file mode 100644
--- /dev/null
+++ b/b2g/gaia/run-b2g.c
@@ -0,0 +1,47 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <libgen.h>
+
+#ifndef B2G_NAME
+#define B2G_NAME "b2g-bin"
+#endif
+#ifndef GAIA_PATH
+#define GAIA_PATH "gaia/profile"
+#endif
+#define NOMEM "Could not allocate enough memory"
+
+void error(char* msg){
+    fprintf(stderr, "ERROR: %s\n", msg);
+}
+
+int main(int argc, char* argv[], char* envp[]){
+    char* cwd = NULL;
+    char* full_path = NULL;
+    char* full_profile_path = NULL;
+    printf("Starting %s\n", B2G_NAME);
+    cwd = realpath(dirname(argv[0]), NULL);
+    full_path = (char*) malloc(strlen(cwd) + strlen(B2G_NAME) + 2);
+    if (!full_path) {
+        error(NOMEM);
+        return -2;
+    }
+    full_profile_path = (char*) malloc(strlen(cwd) + strlen(GAIA_PATH) + 2);
+    if (!full_profile_path) {
+        error(NOMEM);
+        return -2;
+    }
+    sprintf(full_path, "%s/%s", cwd, B2G_NAME);
+    sprintf(full_profile_path, "%s/%s", cwd, GAIA_PATH);
+    free(cwd);
+    printf("Running: %s -profile %s\n", full_path, full_profile_path);
+    fflush(stdout);
+    fflush(stderr);
+    execle(full_path, full_path, "-profile", full_profile_path, NULL, envp);
+    error("unable to start");
+    perror(argv[0]);
+    free(full_path);
+    free(full_profile_path);
+    return -1;
+}
--- a/browser/base/content/pageinfo/pageInfo.xul
+++ b/browser/base/content/pageinfo/pageInfo.xul
@@ -59,17 +59,17 @@
     <command id="cmd_cookieToggle"  oncommand="onRadioClick('cookie');"/>
     <command id="cmd_installToggle" oncommand="onRadioClick('install');"/>
     <command id="cmd_fullscreenToggle" oncommand="onRadioClick('fullscreen');"/>
     <command id="cmd_geoToggle"     oncommand="onRadioClick('geo');"/>
     <command id="cmd_indexedDBToggle" oncommand="onRadioClick('indexedDB');"/>
     <command id="cmd_pluginsToggle" oncommand="onRadioClick('plugins');"/>
   </commandset>
 
-  <keyset>
+  <keyset id="pageInfoKeySet">
     <key key="&closeWindow.key;" modifiers="accel" command="cmd_close"/>
     <key keycode="VK_ESCAPE"                       command="cmd_close"/>
 #ifdef XP_MACOSX
     <key key="."                 modifiers="meta"  command="cmd_close"/>
 #else
     <key keycode="VK_F1"                           command="cmd_help"/>
 #endif
     <key key="&copy.key;"        modifiers="accel" command="cmd_copy"/>
@@ -97,60 +97,60 @@
       <!-- Others added by overlay -->
     </radiogroup>
   </windowdragbox>
 
   <deck id="mainDeck" flex="1">
     <!-- General page information -->
     <vbox id="generalPanel">
       <textbox class="header" readonly="true" id="titletext"/>
-      <grid>
+      <grid id="generalGrid">
         <columns>
           <column/>
           <column class="gridSeparator"/>
           <column flex="1"/>
         </columns>
-        <rows>
-          <row>
+        <rows id="generalRows">
+          <row id="generalURLRow">
             <label control="urltext" value="&generalURL;"/>
             <separator/>
             <textbox readonly="true" id="urltext"/>
           </row>
-          <row>
+          <row id="generalSeparatorRow1">
             <separator class="thin"/>
           </row>
-          <row>
+          <row id="generalTypeRow">
             <label control="typetext" value="&generalType;"/>
             <separator/>
             <textbox readonly="true" id="typetext"/>
           </row>
-          <row>
+          <row id="generalModeRow">
             <label control="modetext" value="&generalMode;"/>
             <separator/>
             <textbox readonly="true" crop="end" id="modetext"/>
           </row>
-          <row>
+          <row id="generalEncodingRow">
             <label control="encodingtext" value="&generalEncoding;"/>
             <separator/>
             <textbox readonly="true" id="encodingtext"/>
           </row>
-          <row>
+          <row id="generalSizeRow">
             <label control="sizetext" value="&generalSize;"/>
             <separator/>
             <textbox readonly="true" id="sizetext"/>
           </row>
-          <row>
+          <row id="generalReferrerRow">
             <label control="refertext" value="&generalReferrer;"/>
             <separator/>
             <textbox readonly="true" id="refertext"/>
           </row>
-          <row>
+          <row id="generalSeparatorRow2">
             <separator class="thin"/>
           </row>
-          <row>
+          <row id="generalModifiedRow">
             <label control="modifiedtext" value="&generalModified;"/>
             <separator/>
             <textbox readonly="true" id="modifiedtext"/>
           </row>
         </rows>
       </grid>
       <separator class="thin"/>
       <groupbox id="metaTags" flex="1" class="collapsable treebox">
@@ -160,24 +160,24 @@
             <treecol id="meta-name"    label="&generalMetaName;"
                      persist="width" flex="1"
                      onclick="gMetaView.onPageMediaSort('meta-name');"/>
             <splitter class="tree-splitter"/>
             <treecol id="meta-content" label="&generalMetaContent;"
                      persist="width" flex="4"
                      onclick="gMetaView.onPageMediaSort('meta-content');"/>
           </treecols>
-          <treechildren flex="1"/>
+          <treechildren id="metatreechildren" flex="1"/>
         </tree>        
       </groupbox>
       <groupbox id="securityBox">
         <caption id="securityBoxCaption" label="&securityHeader;"/>
         <description id="general-security-identity" class="header"/>
         <description id="general-security-privacy"  class="header"/>
-        <hbox align="right">
+        <hbox id="securityDetailsButtonBox" align="right">
           <button id="security-view-details" label="&generalSecurityDetails;"
                   accesskey="&generalSecurityDetails.accesskey;"
                   oncommand="onClickMore();"/>
         </hbox>
       </groupbox>
     </vbox>
 
     <!-- Media information -->
@@ -200,199 +200,200 @@
           <treecol sortSeparators="true" hidden="true" persist="hidden width" flex="4"
                         width="4"  id="image-alt"    label="&mediaAltHeader;"
                         onclick="gImageView.onPageMediaSort('image-alt');"/>
           <splitter class="tree-splitter"/>
           <treecol sortSeparators="true" hidden="true" persist="hidden width" flex="1"
                         width="1"  id="image-count"    label="&mediaCount;"
                         onclick="gImageView.onPageMediaSort('image-count');"/>
         </treecols>
-        <treechildren flex="1"/>
+        <treechildren id="imagetreechildren" flex="1"/>
       </tree>
       <splitter orient="vertical" id="mediaSplitter"/>
       <vbox flex="1" id="mediaPreviewBox" collapsed="true">
         <grid id="mediaGrid">
           <columns>
             <column id="mediaLabelColumn"/>
             <column class="gridSeparator"/>
             <column flex="1"/>
           </columns>
-          <rows>
-            <row>
+          <rows id="mediaRows">
+            <row id="mediaLocationRow">
               <label control="imageurltext" value="&mediaLocation;"/>
               <separator/>
               <textbox readonly="true" id="imageurltext"/>
             </row>
-            <row>
+            <row id="mediaTypeRow">
               <label control="imagetypetext" value="&generalType;"/>
               <separator/>
               <textbox readonly="true" id="imagetypetext"/>
             </row>
-            <row>
+            <row id="mediaSizeRow">
               <label control="imagesizetext" value="&generalSize;"/>
               <separator/>
               <textbox readonly="true" id="imagesizetext"/>
             </row>
-            <row>
+            <row id="mediaDimensionRow">
               <label control="imagedimensiontext" value="&mediaDimension;"/>
               <separator/>
               <textbox readonly="true" id="imagedimensiontext"/>
             </row>
-            <row>
+            <row id="mediaTextRow">
               <label control="imagetext" value="&mediaText;"/>
               <separator/>
               <textbox readonly="true" id="imagetext"/>
             </row>
-            <row>
+            <row id="mediaLongdescRow">
               <label control="imagelongdesctext" value="&mediaLongdesc;"/>
               <separator/>
               <textbox readonly="true" id="imagelongdesctext"/>
             </row>
           </rows>
         </grid>
-        <hbox align="end">
-          <vbox>
+        <hbox id="imageSaveBox" align="end">
+          <vbox id="blockImageBox">
             <checkbox id="blockImage" hidden="true" oncommand="onBlockImage()"
                       accesskey="&mediaBlockImage.accesskey;"/>
             <label control="thepreviewimage" value="&mediaPreview;" class="header"/>
           </vbox>
-          <spacer flex="1"/>
+          <spacer id="imageSaveBoxSpacer" flex="1"/>
           <button label="&mediaSaveAs;" accesskey="&mediaSaveAs.accesskey;"
                   icon="save" id="imagesaveasbutton"
                   oncommand="saveMedia();"/>
         </hbox>
-        <vbox class="inset iframe" flex="1" pack="center">
+        <vbox id="imagecontainerbox" class="inset iframe" flex="1" pack="center">
           <hbox id="theimagecontainer" pack="center">
             <image id="thepreviewimage"/>
           </hbox>
           <hbox id="brokenimagecontainer" pack="center" collapsed="true">
             <image id="brokenimage" src="resource://gre-resources/broken-image.png"/>
           </hbox>
         </vbox>
       </vbox>
       <hbox id="mediaSaveBox" collapsed="true">
-        <spacer flex="1"/>
+        <spacer id="mediaSaveBoxSpacer" flex="1"/>
         <button label="&mediaSaveAs;" accesskey="&mediaSaveAs2.accesskey;"
-                icon="save" oncommand="saveMedia();"/>
+                icon="save" id="mediasaveasbutton"
+                oncommand="saveMedia();"/>
       </hbox>
     </vbox>
 
     <!-- Feeds -->
     <vbox id="feedPanel">
       <richlistbox id="feedListbox" flex="1"/>
     </vbox>
 
     <!-- Permissions -->
     <vbox id="permPanel">
-      <hbox>
+      <hbox id="permHostBox">
         <label value="&permissionsFor;" control="hostText" />
         <textbox id="hostText" class="header" readonly="true"
                  crop="end" flex="1"/>
       </hbox>
 
       <vbox id="permList" flex="1">
-        <vbox class="permission">
+        <vbox class="permission" id="permImageRow">
           <label class="permissionLabel" id="permImageLabel"
                  value="&permImage;" control="imageRadioGroup"/>
-          <hbox role="group" aria-labelledby="permImageLabel">
+          <hbox id="permImageBox" role="group" aria-labelledby="permImageLabel">
             <checkbox id="imageDef" command="cmd_imageDef" label="&permUseDefault;"/>
             <spacer flex="1"/>
             <radiogroup id="imageRadioGroup" orient="horizontal">
               <radio id="image#1" command="cmd_imageToggle" label="&permAllow;"/>
               <radio id="image#2" command="cmd_imageToggle" label="&permBlock;"/>
             </radiogroup>
           </hbox>
         </vbox>
-        <vbox class="permission">
+        <vbox class="permission" id="permPopupRow">
           <label class="permissionLabel" id="permPopupLabel"
                  value="&permPopup;" control="popupRadioGroup"/>
-          <hbox role="group" aria-labelledby="permPopupLabel">
+          <hbox id="permPopupBox" role="group" aria-labelledby="permPopupLabel">
             <checkbox id="popupDef" command="cmd_popupDef" label="&permUseDefault;"/>
             <spacer flex="1"/>
             <radiogroup id="popupRadioGroup" orient="horizontal">
               <radio id="popup#1" command="cmd_popupToggle" label="&permAllow;"/>
               <radio id="popup#2" command="cmd_popupToggle" label="&permBlock;"/>
             </radiogroup>
           </hbox>
         </vbox>
-        <vbox class="permission">
+        <vbox class="permission" id="permCookieRow">
           <label class="permissionLabel" id="permCookieLabel"
                  value="&permCookie;" control="cookieRadioGroup"/>
-          <hbox role="group" aria-labelledby="permCookieLabel">
+          <hbox id="permCookieBox" role="group" aria-labelledby="permCookieLabel">
             <checkbox id="cookieDef" command="cmd_cookieDef" label="&permUseDefault;"/>
             <spacer flex="1"/>
             <radiogroup id="cookieRadioGroup" orient="horizontal">
               <radio id="cookie#1" command="cmd_cookieToggle" label="&permAllow;"/>
               <radio id="cookie#8" command="cmd_cookieToggle" label="&permAllowSession;"/>
               <radio id="cookie#2" command="cmd_cookieToggle" label="&permBlock;"/>
             </radiogroup>
           </hbox>
         </vbox>
-        <vbox class="permission">
+        <vbox class="permission" id="permInstallRow">
           <label class="permissionLabel" id="permInstallLabel"
                  value="&permInstall;" control="installRadioGroup"/>
-          <hbox role="group" aria-labelledby="permInstallLabel">
+          <hbox id="permInstallBox" role="group" aria-labelledby="permInstallLabel">
             <checkbox id="installDef" command="cmd_installDef" label="&permUseDefault;"/>
             <spacer flex="1"/>
             <radiogroup id="installRadioGroup" orient="horizontal">
               <radio id="install#1" command="cmd_installToggle" label="&permAllow;"/>
               <radio id="install#2" command="cmd_installToggle" label="&permBlock;"/>
             </radiogroup>
           </hbox>
         </vbox>
-        <vbox class="permission">
+        <vbox class="permission" id="permGeoRow" >
           <label class="permissionLabel" id="permGeoLabel"
                  value="&permGeo;" control="geoRadioGroup"/>
-          <hbox role="group" aria-labelledby="permGeoLabel">
+          <hbox id="permGeoBox" role="group" aria-labelledby="permGeoLabel">
             <checkbox id="geoDef" command="cmd_geoDef" label="&permAskAlways;"/>
             <spacer flex="1"/>
             <radiogroup id="geoRadioGroup" orient="horizontal">
               <radio id="geo#1" command="cmd_geoToggle" label="&permAllow;"/>
               <radio id="geo#2" command="cmd_geoToggle" label="&permBlock;"/>
             </radiogroup>
           </hbox>
         </vbox>
-        <vbox class="permission">
+        <vbox class="permission" id="permIndexedDBRow">
           <label class="permissionLabel" id="permIndexedDBLabel"
                  value="&permIndexedDB;" control="indexedDBRadioGroup"/>
-          <hbox role="group" aria-labelledby="permIndexedDBLabel">
+          <hbox id="permIndexedDBBox" role="group" aria-labelledby="permIndexedDBLabel">
             <checkbox id="indexedDBDef" command="cmd_indexedDBDef" label="&permUseDefault;"/>
             <spacer flex="1"/>
             <radiogroup id="indexedDBRadioGroup" orient="horizontal">
               <!-- Ask and Allow are purposefully reversed here! -->
               <radio id="indexedDB#1" command="cmd_indexedDBToggle" label="&permAskAlways;"/>
               <radio id="indexedDB#0" command="cmd_indexedDBToggle" label="&permAllow;"/>
               <radio id="indexedDB#2" command="cmd_indexedDBToggle" label="&permBlock;"/>
             </radiogroup>
           </hbox>
-          <hbox>
+          <hbox id="permIndexedDBBox2">
             <spacer flex="1"/>
-            <vbox pack="center">
+            <vbox id="permIndexedDBStatusBox" pack="center">
               <label id="indexedDBStatus" control="indexedDBClear" hidden="true"/>
             </vbox>
             <button id="indexedDBClear" label="&permClearStorage;" hidden="true"
                     accesskey="&permClearStorage.accesskey;" onclick="onIndexedDBClear();"/>
           </hbox>
         </vbox>
         <vbox class="permission" id="permPluginsRow">
           <label class="permissionLabel" id="permPluginsLabel"
                  value="&permPlugins;" control="pluginsRadioGroup"/>
-          <hbox role="group" aria-labelledby="permPluginsLabel">
+          <hbox id="permPluginsBox" role="group" aria-labelledby="permPluginsLabel">
             <checkbox id="pluginsDef" command="cmd_pluginsDef" label="&permAskAlways;"/>
             <spacer flex="1"/>
             <radiogroup id="pluginsRadioGroup" orient="horizontal">
               <radio id="plugins#1" command="cmd_pluginsToggle" label="&permAllow;"/>
               <radio id="plugins#2" command="cmd_pluginsToggle" label="&permBlock;"/>
             </radiogroup>
           </hbox>
         </vbox>
-        <vbox class="permission">
+        <vbox class="permission" id="permFullscreenRow">
           <label class="permissionLabel" id="permFullscreenLabel"
                  value="&permFullscreen;" control="fullscreenRadioGroup"/>
-          <hbox role="group" aria-labelledby="permFullscreenLabel">
+          <hbox id="permFullscreenBox" role="group" aria-labelledby="permFullscreenLabel">
             <checkbox id="fullscreenDef" command="cmd_fullscreenDef" label="&permUseDefault;"/>
             <spacer flex="1"/>
             <radiogroup id="fullscreenRadioGroup" orient="horizontal">
               <radio id="fullscreen#0" command="cmd_fullscreenToggle" label="&permAskAlways;"/>
               <radio id="fullscreen#1" command="cmd_fullscreenToggle" label="&permAllow;"/>
               <radio id="fullscreen#2" command="cmd_fullscreenToggle" label="&permBlock;"/>
             </radiogroup>
           </hbox>
@@ -400,95 +401,102 @@
       </vbox>
     </vbox>
 
     <!-- Security & Privacy -->
     <vbox id="securityPanel">
       <!-- Identity Section -->
       <groupbox id="security-identity-groupbox" flex="1">
         <caption id="security-identity" label="&securityView.identity.header;"/>
-        <grid flex="1">
+        <grid id="security-identity-grid" flex="1">
           <columns>
             <column/>
             <column flex="1"/>
           </columns>
-          <rows>
-            <row><!-- Domain -->
+          <rows id="security-identity-rows">
+            <!-- Domain -->
+            <row id="security-identity-domain-row">
               <label id="security-identity-domain-label"
                      class="fieldLabel"
                      value="&securityView.identity.domain;"
                      control="security-identity-domain-value"/>
               <textbox id="security-identity-domain-value"
                        class="fieldValue" readonly="true"/>
             </row>
-            <row><!-- Owner -->
+            <!-- Owner -->
+            <row id="security-identity-owner-row">
               <label id="security-identity-owner-label"
                      class="fieldLabel"
                      value="&securityView.identity.owner;"
                      control="security-identity-owner-value"/>
               <textbox id="security-identity-owner-value"
                        class="fieldValue" readonly="true"/>
             </row>
-            <row><!-- Verifier -->
+            <!-- Verifier -->
+            <row id="security-identity-verifier-row">
               <label id="security-identity-verifier-label"
                      class="fieldLabel"
                      value="&securityView.identity.verifier;"
                      control="security-identity-verifier-value"/>
               <textbox id="security-identity-verifier-value"
                        class="fieldValue" readonly="true" />
             </row>
           </rows>
         </grid>
         <spacer flex="1"/>
-        <hbox pack="end"><!-- Cert button -->
+        <!-- Cert button -->
+        <hbox id="security-view-cert-box" pack="end">
           <button id="security-view-cert" label="&securityView.certView;"
                   accesskey="&securityView.accesskey;"
                   oncommand="security.viewCert();"/>
         </hbox>
       </groupbox>
       
       <!-- Privacy & History section -->
       <groupbox id="security-privacy-groupbox" flex="1">
         <caption id="security-privacy" label="&securityView.privacy.header;" />
-        <grid>
+        <grid id="security-privacy-grid">
           <columns>
             <column flex="1"/>
             <column flex="1"/>
           </columns>
-          <rows>
-            <row><!-- History -->
+          <rows id="security-privacy-rows">
+            <!-- History -->
+            <row id="security-privacy-history-row">
               <label id="security-privacy-history-label"
                            control="security-privacy-history-value"
                            class="fieldLabel">&securityView.privacy.history;</label>
               <textbox id="security-privacy-history-value"
                        class="fieldValue"
                        value="&securityView.unknown;"
                        readonly="true"/>
             </row>
-            <row><!-- Cookies -->
+            <!-- Cookies -->
+            <row id="security-privacy-cookies-row">
               <label id="security-privacy-cookies-label"
                            control="security-privacy-cookies-value"
                            class="fieldLabel">&securityView.privacy.cookies;</label>
-              <hbox align="center">
+              <hbox id="security-privacy-cookies-box" align="center">
                 <textbox id="security-privacy-cookies-value"
                          class="fieldValue"
                          value="&securityView.unknown;"
                          flex="1"
                          readonly="true"/>
                 <button id="security-view-cookies"
                         label="&securityView.privacy.viewCookies;"
                         accesskey="&securityView.privacy.viewCookies.accessKey;"
                         oncommand="security.viewCookies();"/>
               </hbox>
             </row>
-            <row><!-- Passwords -->
+            <!-- Passwords -->
+            <row id="security-privacy-passwords-row">
               <label id="security-privacy-passwords-label"
                             control="security-privacy-passwords-value"
                             class="fieldLabel">&securityView.privacy.passwords;</label>
-              <hbox align="center">
+              <hbox id="security-privacy-passwords-box" align="center">
                 <textbox id="security-privacy-passwords-value"
                          class="fieldValue"
                          value="&securityView.unknown;"
                          flex="1"
                          readonly="true"/>
                 <button id="security-view-password"
                         label="&securityView.privacy.viewPasswords;"
                         accesskey="&securityView.privacy.viewPasswords.accessKey;"
@@ -497,17 +505,17 @@
             </row>
           </rows>
         </grid>
       </groupbox>
       
       <!-- Technical Details section -->
       <groupbox id="security-technical-groupbox" flex="1">
         <caption id="security-technical" label="&securityView.technical.header;" />
-        <vbox flex="1">
+        <vbox id="security-technical-box" flex="1">
           <label id="security-technical-shortform" class="fieldValue"/>
           <description id="security-technical-longform1" class="fieldLabel"/>
           <description id="security-technical-longform2" class="fieldLabel"/>
         </vbox>
       </groupbox>
     </vbox>
     <!-- Others added by overlay -->
   </deck>
deleted file mode 100644
--- a/build/mobile/b2gemulator.py
+++ /dev/null
@@ -1,87 +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/.
-
-
-import os
-import platform
-
-from emulator import Emulator
-
-
-class B2GEmulator(Emulator):
-
-    def __init__(self, homedir=None, noWindow=False, logcat_dir=None, arch="x86",
-                 emulatorBinary=None, res='480x800', userdata=None,
-                 memory='512', partition_size='512'):
-        super(B2GEmulator, self).__init__(noWindow=noWindow, logcat_dir=logcat_dir,
-                                          arch=arch, emulatorBinary=emulatorBinary,
-                                          res=res, userdata=userdata,
-                                          memory=memory, partition_size=partition_size)
-        self.homedir = homedir
-        if self.homedir is not None:
-            self.homedir = os.path.expanduser(homedir)
-
-    def _check_file(self, filePath):
-        if not os.path.exists(filePath):
-            raise Exception(('File not found: %s; did you pass the B2G home '
-                             'directory as the homedir parameter, or set '
-                             'B2G_HOME correctly?') % filePath)
-
-    def _check_for_adb(self, host_dir):
-        if self._default_adb() == 0:
-            return
-        adb_paths = [os.path.join(self.homedir,'glue','gonk','out','host',
-                      host_dir ,'bin','adb'),os.path.join(self.homedir, 'out',
-                      'host', host_dir,'bin','adb'),os.path.join(self.homedir,
-                      'bin','adb')]
-        for option in adb_paths:
-            if os.path.exists(option):
-                self.adb = option
-                return
-        raise Exception('adb not found!')
-
-    def _locate_files(self):
-        if self.homedir is None:
-            self.homedir = os.getenv('B2G_HOME')
-        if self.homedir is None:
-            raise Exception('Must define B2G_HOME or pass the homedir parameter')
-        self._check_file(self.homedir)
-
-        if self.arch not in ("x86", "arm"):
-            raise Exception("Emulator architecture must be one of x86, arm, got: %s" %
-                            self.arch)
-
-        host_dir = "linux-x86"
-        if platform.system() == "Darwin":
-            host_dir = "darwin-x86"
-
-        host_bin_dir = os.path.join("out", "host", host_dir, "bin")
-
-        if self.arch == "x86":
-            binary = os.path.join(host_bin_dir, "emulator-x86")
-            kernel = "prebuilts/qemu-kernel/x86/kernel-qemu"
-            sysdir = "out/target/product/generic_x86"
-            self.tail_args = []
-        else:
-            binary = os.path.join(host_bin_dir, "emulator")
-            kernel = "prebuilts/qemu-kernel/arm/kernel-qemu-armv7"
-            sysdir = "out/target/product/generic"
-            self.tail_args = ["-cpu", "cortex-a8"]
-
-        self._check_for_adb(host_dir)
-
-        if not self.binary:
-            self.binary = os.path.join(self.homedir, binary)
-
-        self._check_file(self.binary)
-
-        self.kernelImg = os.path.join(self.homedir, kernel)
-        self._check_file(self.kernelImg)
-
-        self.sysDir = os.path.join(self.homedir, sysdir)
-        self._check_file(self.sysDir)
-
-        if not self.dataImg:
-            self.dataImg = os.path.join(self.sysDir, 'userdata.img')
-        self._check_file(self.dataImg)
deleted file mode 100644
--- a/build/mobile/devicemanager-utils.py
+++ /dev/null
@@ -1,56 +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/.
-
-import devicemanager
-import sys
-import os
-
-def copy(dm, gre_path):
-    file = sys.argv[2]
-    if len(sys.argv) >= 4:
-        path = sys.argv[3]
-    else:
-        path = gre_path
-    if os.path.isdir(file):
-        dm.pushDir(file, path.replace('\\','/'))
-    else:
-        dm.pushFile(file, path.replace('\\','/'))
-
-def delete(dm, gre_path):
-    file = sys.argv[2]
-    dm.removeFile(file)
-
-def main():
-    ip_addr = os.environ.get("DEVICE_IP")
-    port = os.environ.get("DEVICE_PORT")
-    gre_path = os.environ.get("REMOTE_GRE_PATH").replace('\\','/')
-
-    if ip_addr == None:
-        print "Error: please define the environment variable DEVICE_IP before running this test"
-        sys.exit(1)
-
-    if port == None:
-        print "Error: please define the environment variable DEVICE_PORT before running this test"
-        sys.exit(1)
-
-    if gre_path == None:
-        print "Error: please define the environment variable REMOTE_GRE_PATH before running this test"
-        sys.exit(1)
-
-    dm = devicemanager.DeviceManager(ip_addr, int(port))
-    dm.sendCMD(['cd '+ gre_path], sleep = 1)
-    dm.debug = 0
-
-    if len(sys.argv) < 3:
-        print "usage: python devicemanager-utils.py <cmd> <path> [arg]"
-    cmd = sys.argv[1]
-    if (cmd == 'copy'):
-        sys.exit(copy(dm, gre_path))
-    if (cmd == 'delete'):
-        sys.exit(delete(dm, gre_path))
-    print "unrecognized command. supported commands are copy and delete"
-    sys.exit(-1)
-
-if __name__ == '__main__':
-    main()
deleted file mode 100755
--- a/build/mobile/devicemanager.py
+++ /dev/null
@@ -1,637 +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/.
-
-import hashlib
-import socket
-import os
-import re
-import StringIO
-
-class FileError(Exception):
-  " Signifies an error which occurs while doing a file operation."
-
-  def __init__(self, msg = ''):
-    self.msg = msg
-
-  def __str__(self):
-    return self.msg
-
-class DMError(Exception):
-  "generic devicemanager exception."
-
-  def __init__(self, msg= ''):
-    self.msg = msg
-
-  def __str__(self):
-    return self.msg
-
-def abstractmethod(method):
-  line = method.func_code.co_firstlineno
-  filename = method.func_code.co_filename
-  def not_implemented(*args, **kwargs):
-    raise NotImplementedError('Abstract method %s at File "%s", line %s '
-                              'should be implemented by a concrete class' %
-                              (repr(method), filename,line))
-  return not_implemented
-
-class DeviceManager:
-
-  @abstractmethod
-  def shell(self, cmd, outputfile, env=None, cwd=None, timeout=None):
-    """
-    executes shell command on device
-
-    timeout is specified in seconds, and if no timeout is given, 
-    we will run until the script returns
-    returns:
-    success: Return code from command
-    failure: None
-    """
-
-  @abstractmethod
-  def pushFile(self, localname, destname):
-    """
-    external function
-    returns:
-    success: True
-    failure: False
-    """
-
-  @abstractmethod
-  def mkDir(self, name):
-    """
-    external function
-    returns:
-    success: directory name
-    failure: None
-    """
-
-  def mkDirs(self, filename):
-    """
-    make directory structure on the device
-    WARNING: does not create last part of the path
-    external function
-    returns:
-    success: directory structure that we created
-    failure: None
-    """
-    parts = filename.split('/')
-    name = ""
-    for part in parts:
-        if (part == parts[-1]): break
-        if (part != ""):
-            name += '/' + part
-            if (not self.dirExists(name)):
-                if (self.mkDir(name) == None):
-                    print "failed making directory: " + str(name)
-                    return None
-    return name
-
-  @abstractmethod
-  def pushDir(self, localDir, remoteDir):
-    """
-    push localDir from host to remoteDir on the device
-    external function
-    returns:
-    success: remoteDir
-    failure: None
-    """
-
-  @abstractmethod
-  def dirExists(self, dirname):
-    """
-    external function
-    returns:
-    success: True
-    failure: False
-    """
-
-  @abstractmethod
-  def fileExists(self, filepath):
-    """
-    Because we always have / style paths we make this a lot easier with some
-    assumptions
-    external function
-    returns:
-    success: True
-    failure: False
-    """
-
-  @abstractmethod
-  def listFiles(self, rootdir):
-    """
-    list files on the device, requires cd to directory first
-    external function
-    returns:
-    success: array of filenames, ['file1', 'file2', ...]
-    failure: None
-    """
-
-  @abstractmethod
-  def removeFile(self, filename):
-    """
-    external function
-    returns:
-    success: output of telnet, i.e. "removing file: /mnt/sdcard/tests/test.txt"
-    failure: None
-    """
-
-  @abstractmethod
-  def removeDir(self, remoteDir):
-    """
-    does a recursive delete of directory on the device: rm -Rf remoteDir
-    external function
-    returns:
-    success: output of telnet, i.e. "removing file: /mnt/sdcard/tests/test.txt"
-    failure: None
-    """
-
-  @abstractmethod
-  def getProcessList(self):
-    """
-    external function
-    returns:
-    success: array of process tuples
-    failure: None
-    """
-
-  @abstractmethod
-  def fireProcess(self, appname, failIfRunning=False):
-    """
-    external function
-    DEPRECATED: Use shell() or launchApplication() for new code
-    returns:
-    success: pid
-    failure: None
-    """
-
-  @abstractmethod
-  def launchProcess(self, cmd, outputFile = "process.txt", cwd = '', env = '', failIfRunning=False):
-    """
-    external function
-    DEPRECATED: Use shell() or launchApplication() for new code
-    returns:
-    success: output filename
-    failure: None
-    """
-
-  def processExist(self, appname):
-    """
-    iterates process list and returns pid if exists, otherwise None
-    external function
-    returns:
-    success: pid
-    failure: None
-    """
-
-    pid = None
-
-    #filter out extra spaces
-    parts = filter(lambda x: x != '', appname.split(' '))
-    appname = ' '.join(parts)
-
-    #filter out the quoted env string if it exists
-    #ex: '"name=value;name2=value2;etc=..." process args' -> 'process args'
-    parts = appname.split('"')
-    if (len(parts) > 2):
-      appname = ' '.join(parts[2:]).strip()
-
-    pieces = appname.split(' ')
-    parts = pieces[0].split('/')
-    app = parts[-1]
-
-    procList = self.getProcessList()
-    if (procList == []):
-      return None
-
-    for proc in procList:
-      procName = proc[1].split('/')[-1]
-      if (procName == app):
-        pid = proc[0]
-        break
-    return pid
-
-
-  @abstractmethod
-  def killProcess(self, appname, forceKill=False):
-    """
-    external function
-    returns:
-    success: True
-    failure: False
-    """
-
-  @abstractmethod
-  def catFile(self, remoteFile):
-    """
-    external function
-    returns:
-    success: filecontents
-    failure: None
-    """
-
-  @abstractmethod
-  def pullFile(self, remoteFile):
-    """
-    external function
-    returns:
-    success: output of pullfile, string
-    failure: None
-    """
-
-  @abstractmethod
-  def getFile(self, remoteFile, localFile = ''):
-    """
-    copy file from device (remoteFile) to host (localFile)
-    external function
-    returns:
-    success: output of pullfile, string
-    failure: None
-    """
-
-  @abstractmethod
-  def getDirectory(self, remoteDir, localDir, checkDir=True):
-    """
-    copy directory structure from device (remoteDir) to host (localDir)
-    external function
-    checkDir exists so that we don't create local directories if the
-    remote directory doesn't exist but also so that we don't call isDir
-    twice when recursing.
-    returns:
-    success: list of files, string
-    failure: None
-    """
-
-  @abstractmethod
-  def isDir(self, remotePath):
-    """
-    external function
-    returns:
-    success: True
-    failure: False
-    Throws a FileError exception when null (invalid dir/filename)
-    """
-
-  @abstractmethod
-  def validateFile(self, remoteFile, localFile):
-    """
-    true/false check if the two files have the same md5 sum
-    external function
-    returns:
-    success: True
-    failure: False
-    """
-
-  @abstractmethod
-  def getRemoteHash(self, filename):
-    """
-    return the md5 sum of a remote file
-    internal function
-    returns:
-    success: MD5 hash for given filename
-    failure: None
-    """
-
-  def getLocalHash(self, filename):
-    """
-    return the md5 sum of a file on the host
-    internal function
-    returns:
-    success: MD5 hash for given filename
-    failure: None
-    """
-
-    file = open(filename, 'rb')
-    if (file == None):
-      return None
-
-    try:
-      mdsum = hashlib.md5()
-    except:
-      return None
-
-    while 1:
-      data = file.read(1024)
-      if not data:
-        break
-      mdsum.update(data)
-
-    file.close()
-    hexval = mdsum.hexdigest()
-    if (self.debug >= 3): print "local hash returned: '" + hexval + "'"
-    return hexval
-
-  @abstractmethod
-  def getDeviceRoot(self):
-    """
-    Gets the device root for the testing area on the device
-    For all devices we will use / type slashes and depend on the device-agent
-    to sort those out.  The agent will return us the device location where we
-    should store things, we will then create our /tests structure relative to
-    that returned path.
-    Structure on the device is as follows:
-    /tests
-          /<fennec>|<firefox>  --> approot
-          /profile
-          /xpcshell
-          /reftest
-          /mochitest
-    external
-    returns:
-    success: path for device root
-    failure: None
-    """
-
-  @abstractmethod
-  def getAppRoot(self):
-    """
-    Either we will have /tests/fennec or /tests/firefox but we will never have
-    both.  Return the one that exists
-    TODO: ensure we can support org.mozilla.firefox
-    external function
-    returns:
-    success: path for app root
-    failure: None
-    """
-
-  def getTestRoot(self, type):
-    """
-    Gets the directory location on the device for a specific test type
-    Type is one of: xpcshell|reftest|mochitest
-    external function
-    returns:
-    success: path for test root
-    failure: None
-    """
-
-    devroot = self.getDeviceRoot()
-    if (devroot == None):
-      return None
-
-    if (re.search('xpcshell', type, re.I)):
-      self.testRoot = devroot + '/xpcshell'
-    elif (re.search('?(i)reftest', type)):
-      self.testRoot = devroot + '/reftest'
-    elif (re.search('?(i)mochitest', type)):
-      self.testRoot = devroot + '/mochitest'
-    return self.testRoot
-
-  def signal(self, processID, signalType, signalAction):
-    """
-    Sends a specific process ID a signal code and action.
-    For Example: SIGINT and SIGDFL to process x
-    """
-    #currently not implemented in device agent - todo
-
-    pass
-
-  def getReturnCode(self, processID):
-    """Get a return code from process ending -- needs support on device-agent"""
-    # TODO: make this real
-
-    return 0
-
-  @abstractmethod
-  def unpackFile(self, file_path, dest_dir=None):
-    """
-    external function
-    returns:
-    success: output of unzip command
-    failure: None
-    """
-
-  @abstractmethod
-  def reboot(self, ipAddr=None, port=30000):
-    """
-    external function
-    returns:
-    success: status from test agent
-    failure: None
-    """
-
-  def validateDir(self, localDir, remoteDir):
-    """
-    validate localDir from host to remoteDir on the device
-    external function
-    returns:
-    success: True
-    failure: False
-    """
-
-    if (self.debug >= 2): print "validating directory: " + localDir + " to " + remoteDir
-    for root, dirs, files in os.walk(localDir):
-      parts = root.split(localDir)
-      for file in files:
-        remoteRoot = remoteDir + '/' + parts[1]
-        remoteRoot = remoteRoot.replace('/', '/')
-        if (parts[1] == ""): remoteRoot = remoteDir
-        remoteName = remoteRoot + '/' + file
-        if (self.validateFile(remoteName, os.path.join(root, file)) <> True):
-            return False
-    return True
-
-  @abstractmethod
-  def getInfo(self, directive=None):
-    """
-    Returns information about the device:
-    Directive indicates the information you want to get, your choices are:
-    os - name of the os
-    id - unique id of the device
-    uptime - uptime of the device
-    uptimemillis - uptime of the device in milliseconds (NOT supported on all
-                   implementations)
-    systime - system time of the device
-    screen - screen resolution
-    memory - memory stats
-    process - list of running processes (same as ps)
-    disk - total, free, available bytes on disk
-    power - power status (charge, battery temp)
-    all - all of them - or call it with no parameters to get all the information
-    returns:
-    success: dict of info strings by directive name
-    failure: None
-    """
-
-  @abstractmethod
-  def installApp(self, appBundlePath, destPath=None):
-    """
-    external function
-    returns:
-    success: output from agent for inst command
-    failure: None
-    """
-
-  @abstractmethod
-  def uninstallAppAndReboot(self, appName, installPath=None):
-    """
-    external function
-    returns:
-    success: True
-    failure: None
-    """
-
-  @abstractmethod
-  def updateApp(self, appBundlePath, processName=None,
-                destPath=None, ipAddr=None, port=30000):
-    """
-    external function
-    returns:
-    success: text status from command or callback server
-    failure: None
-    """
-
-  @abstractmethod
-  def getCurrentTime(self):
-    """
-    external function
-    returns:
-    success: time in ms
-    failure: None
-    """
-
-  def recordLogcat(self):
-    """
-    external function
-    returns:
-    success: file is created in <testroot>/logcat.log
-    failure:
-    """
-    #TODO: spawn this off in a separate thread/process so we can collect all the logcat information
-
-    # Right now this is just clearing the logcat so we can only see what happens after this call.
-    buf = StringIO.StringIO()
-    self.shell(['/system/bin/logcat', '-c'], buf, root=True)
-
-  def getLogcat(self):
-    """
-    external function
-    returns: data from the local file
-    success: file is in 'filename'
-    failure: None
-    """
-    buf = StringIO.StringIO()
-    if self.shell(["/system/bin/logcat", "-d", "dalvikvm:S", "ConnectivityService:S", "WifiMonitor:S", "WifiStateTracker:S", "wpa_supplicant:S", "NetworkStateTracker:S"], buf, root=True) != 0:
-      return None
-
-    return str(buf.getvalue()[0:-1]).rstrip().split('\r')
-
-  @abstractmethod
-  def chmodDir(self, remoteDir):
-    """
-    external function
-    returns:
-    success: True
-    failure: False
-    """
-
-  @staticmethod
-  def _escapedCommandLine(cmd):
-    """ Utility function to return escaped and quoted version of command line """
-    quotedCmd = []
-
-    for arg in cmd:
-      arg.replace('&', '\&')
-
-      needsQuoting = False
-      for char in [ ' ', '(', ')', '"', '&' ]:
-        if arg.find(char) >= 0:
-          needsQuoting = True
-          break
-      if needsQuoting:
-        arg = '\'%s\'' % arg
-
-      quotedCmd.append(arg)
-
-    return " ".join(quotedCmd)
-
-
-class NetworkTools:
-  def __init__(self):
-    pass
-
-  # Utilities to get the local ip address
-  def getInterfaceIp(self, ifname):
-    if os.name != "nt":
-      import fcntl
-      import struct
-      s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
-      return socket.inet_ntoa(fcntl.ioctl(
-                              s.fileno(),
-                              0x8915,  # SIOCGIFADDR
-                              struct.pack('256s', ifname[:15])
-                              )[20:24])
-    else:
-      return None
-
-  def getLanIp(self):
-    try:
-      ip = socket.gethostbyname(socket.gethostname())
-    except socket.gaierror:
-      ip = socket.gethostbyname(socket.gethostname() + ".local") # for Mac OS X
-    if ip.startswith("127.") and os.name != "nt":
-      interfaces = ["eth0","eth1","eth2","wlan0","wlan1","wifi0","ath0","ath1","ppp0"]
-      for ifname in interfaces:
-        try:
-          ip = self.getInterfaceIp(ifname)
-          break;
-        except IOError:
-          pass
-    return ip
-
-  # Gets an open port starting with the seed by incrementing by 1 each time
-  def findOpenPort(self, ip, seed):
-    try:
-      s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
-      s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
-      connected = False
-      if isinstance(seed, basestring):
-        seed = int(seed)
-      maxportnum = seed + 5000 # We will try at most 5000 ports to find an open one
-      while not connected:
-        try:
-          s.bind((ip, seed))
-          connected = True
-          s.close()
-          break
-        except:
-          if seed > maxportnum:
-            print "Could not find open port after checking 5000 ports"
-          raise
-        seed += 1
-    except:
-      print "Socket error trying to find open port"
-
-    return seed
-
-def _pop_last_line(file):
-  '''
-  Utility function to get the last line from a file (shared between ADB and
-  SUT device managers). Function also removes it from the file. Intended to
-  strip off the return code from a shell command.
-  '''
-  bytes_from_end = 1
-  file.seek(0, 2)
-  length = file.tell() + 1
-  while bytes_from_end < length:
-    file.seek((-1)*bytes_from_end, 2)
-    data = file.read()
-
-    if bytes_from_end == length-1 and len(data) == 0: # no data, return None
-      return None
-
-    if data[0] == '\n' or bytes_from_end == length-1:
-      # found the last line, which should have the return value
-      if data[0] == '\n':
-        data = data[1:]
-
-      # truncate off the return code line
-      file.truncate(length - bytes_from_end)
-      file.seek(0,2)
-      file.write('\0')
-
-      return data
-
-    bytes_from_end += 1
-
-  return None
deleted file mode 100644
--- a/build/mobile/devicemanagerADB.py
+++ /dev/null
@@ -1,900 +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/.
-
-import subprocess
-from devicemanager import DeviceManager, DMError, _pop_last_line
-import re
-import os
-import tempfile
-import time
-
-class DeviceManagerADB(DeviceManager):
-
-  def __init__(self, host=None, port=20701, retrylimit=5, packageName='fennec',
-               adbPath='adb', deviceSerial=None, deviceRoot=None):
-    self.host = host
-    self.port = port
-    self.retrylimit = retrylimit
-    self.retries = 0
-    self._sock = None
-    self.useRunAs = False
-    self.haveRoot = False
-    self.useDDCopy = False
-    self.useZip = False
-    self.packageName = None
-    self.tempDir = None
-    self.deviceRoot = deviceRoot
-
-    # the path to adb, or 'adb' to assume that it's on the PATH
-    self.adbPath = adbPath
-
-    # The serial number of the device to use with adb, used in cases
-    # where multiple devices are being managed by the same adb instance.
-    self.deviceSerial = deviceSerial
-
-    if packageName == 'fennec':
-      if os.getenv('USER'):
-        self.packageName = 'org.mozilla.fennec_' + os.getenv('USER')
-      else:
-        self.packageName = 'org.mozilla.fennec_'
-    elif packageName:
-      self.packageName = packageName
-
-    # verify that we can run the adb command. can't continue otherwise
-    self.verifyADB()
-
-    # try to connect to the device over tcp/ip if we have a hostname
-    if self.host:
-      self.connectRemoteADB()
-
-    # verify that we can connect to the device. can't continue
-    self.verifyDevice()
-
-    # set up device root
-    self.setupDeviceRoot()
-
-    # Can we use run-as? (currently not required)
-    try:
-      self.verifyRunAs()
-    except DMError:
-      pass
-
-    # Can we run things as root? (currently not required)
-    useRunAsTmp = self.useRunAs
-    self.useRunAs = False
-    try:
-      self.verifyRoot()
-    except DMError:
-      try:
-        self.checkCmd(["root"])
-        # The root command does not fail even if ADB cannot get
-        # root rights (e.g. due to production builds), so we have
-        # to check again ourselves that we have root now.
-        self.verifyRoot()
-      except DMError:
-        if useRunAsTmp:
-          print "restarting as root failed, but run-as available"
-        else:
-          print "restarting as root failed"
-    self.useRunAs = useRunAsTmp
-
-    # can we use zip to speed up some file operations? (currently not
-    # required)
-    try:
-      self.verifyZip()
-    except DMError:
-      pass
-
-  def __del__(self):
-    if self.host:
-      self.disconnectRemoteADB()
-
-  # external function: executes shell command on device.
-  # timeout is specified in seconds, and if no timeout is given, 
-  # we will run until the script returns
-  # returns:
-  # success: <return code>
-  # failure: None
-  def shell(self, cmd, outputfile, env=None, cwd=None, timeout=None, root=False):
-    # FIXME: this function buffers all output of the command into memory,
-    # always. :(
-
-    # Getting the return code is more complex than you'd think because adb
-    # doesn't actually return the return code from a process, so we have to
-    # capture the output to get it
-    if root:
-      cmdline = "su -c \"%s\"" % self._escapedCommandLine(cmd)
-    else:
-      cmdline = self._escapedCommandLine(cmd)
-    cmdline += "; echo $?"
-
-    # prepend cwd and env to command if necessary
-    if cwd:
-      cmdline = "cd %s; %s" % (cwd, cmdline)
-    if env:
-      envstr = '; '.join(map(lambda x: 'export %s=%s' % (x[0], x[1]), env.iteritems()))
-      cmdline = envstr + "; " + cmdline
-
-    # all output should be in stdout
-    args=[self.adbPath]
-    if self.deviceSerial:
-        args.extend(['-s', self.deviceSerial])
-    args.extend(["shell", cmdline])
-    proc = subprocess.Popen(args,
-                            stdout=subprocess.PIPE, stderr=subprocess.PIPE)
-    if timeout:
-        timeout = int(timeout)
-        start_time = time.time()
-        ret_code = proc.poll()
-        while ((time.time() - start_time) <= timeout) and ret_code == None:
-            time.sleep(1)
-            ret_code = proc.poll()
-        if ret_code == None:
-            proc.kill()
-            raise DMError("Timeout exceeded for shell call")
-    (stdout, stderr) = proc.communicate()
-    outputfile.write(stdout.rstrip('\n'))
-
-    lastline = _pop_last_line(outputfile)
-    if lastline:
-      m = re.search('([0-9]+)', lastline)
-      if m:
-        return_code = m.group(1)
-        outputfile.seek(-2, 2)
-        outputfile.truncate() # truncate off the return code
-        return int(return_code)
-
-    return None
-
-  def connectRemoteADB(self):
-    self.checkCmd(["connect", self.host + ":" + str(self.port)])
-
-  def disconnectRemoteADB(self):
-    self.checkCmd(["disconnect", self.host + ":" + str(self.port)])
-
-  # external function
-  # returns:
-  #  success: True
-  #  failure: False
-  def pushFile(self, localname, destname):
-    try:
-      if (os.name == "nt"):
-        destname = destname.replace('\\', '/')
-      if (self.useRunAs):
-        remoteTmpFile = self.getTempDir() + "/" + os.path.basename(localname)
-        self.checkCmd(["push", os.path.realpath(localname), remoteTmpFile])
-        if self.useDDCopy:
-          self.checkCmdAs(["shell", "dd", "if=" + remoteTmpFile, "of=" + destname])
-        else:
-          self.checkCmdAs(["shell", "cp", remoteTmpFile, destname])
-        self.checkCmd(["shell", "rm", remoteTmpFile])
-      else:
-        self.checkCmd(["push", os.path.realpath(localname), destname])
-      if (self.isDir(destname)):
-        destname = destname + "/" + os.path.basename(localname)
-      return True
-    except:
-      return False
-
-  # external function
-  # returns:
-  #  success: directory name
-  #  failure: None
-  def mkDir(self, name):
-    try:
-      result = self.runCmdAs(["shell", "mkdir", name]).stdout.read()
-      if 'read-only file system' in result.lower():
-        return None
-      if 'file exists' in result.lower():
-        return name
-      return name
-    except:
-      return None
-
-  # push localDir from host to remoteDir on the device
-  # external function
-  # returns:
-  #  success: remoteDir
-  #  failure: None
-  def pushDir(self, localDir, remoteDir):
-    # adb "push" accepts a directory as an argument, but if the directory
-    # contains symbolic links, the links are pushed, rather than the linked
-    # files; we either zip/unzip or push file-by-file to get around this 
-    # limitation
-    try:
-      if (not self.dirExists(remoteDir)):
-        self.mkDirs(remoteDir+"/x")
-      if (self.useZip):
-        try:
-          localZip = tempfile.mktemp()+".zip"
-          remoteZip = remoteDir + "/adbdmtmp.zip"
-          subprocess.check_output(["zip", "-r", localZip, '.'], cwd=localDir)
-          self.pushFile(localZip, remoteZip)
-          os.remove(localZip)
-          data = self.runCmdAs(["shell", "unzip", "-o", remoteZip, "-d", remoteDir]).stdout.read()
-          self.checkCmdAs(["shell", "rm", remoteZip])
-          if (re.search("unzip: exiting", data) or re.search("Operation not permitted", data)):
-            raise Exception("unzip failed, or permissions error")
-        except:
-          print "zip/unzip failure: falling back to normal push"
-          self.useZip = False
-          self.pushDir(localDir, remoteDir)
-      else:
-        for root, dirs, files in os.walk(localDir, followlinks=True):
-          relRoot = os.path.relpath(root, localDir)
-          for file in files:
-            localFile = os.path.join(root, file)
-            remoteFile = remoteDir + "/"
-            if (relRoot!="."):
-              remoteFile = remoteFile + relRoot + "/"
-            remoteFile = remoteFile + file
-            self.pushFile(localFile, remoteFile)
-          for dir in dirs:
-            targetDir = remoteDir + "/"
-            if (relRoot!="."):
-              targetDir = targetDir + relRoot + "/"
-            targetDir = targetDir + dir
-            if (not self.dirExists(targetDir)):
-              self.mkDir(targetDir)
-      return remoteDir
-    except:
-      print "pushing " + localDir + " to " + remoteDir + " failed"
-      return None
-
-  # external function
-  # returns:
-  #  success: True
-  #  failure: False
-  def dirExists(self, dirname):
-    return self.isDir(dirname)
-
-  # Because we always have / style paths we make this a lot easier with some
-  # assumptions
-  # external function
-  # returns:
-  #  success: True
-  #  failure: False
-  def fileExists(self, filepath):
-    p = self.runCmd(["shell", "ls", "-a", filepath])
-    data = p.stdout.readlines()
-    if (len(data) == 1):
-      if (data[0].rstrip() == filepath):
-        return True
-    return False
-
-  def removeFile(self, filename):
-    return self.runCmd(["shell", "rm", filename]).stdout.read()
-
-  # does a recursive delete of directory on the device: rm -Rf remoteDir
-  # external function
-  # returns:
-  #  success: output of telnet, i.e. "removing file: /mnt/sdcard/tests/test.txt"
-  #  failure: None
-  def removeSingleDir(self, remoteDir):
-    return self.runCmd(["shell", "rmdir", remoteDir]).stdout.read()
-
-  # does a recursive delete of directory on the device: rm -Rf remoteDir
-  # external function
-  # returns:
-  #  success: output of telnet, i.e. "removing file: /mnt/sdcard/tests/test.txt"
-  #  failure: None
-  def removeDir(self, remoteDir):
-      out = ""
-      if (self.isDir(remoteDir)):
-          files = self.listFiles(remoteDir.strip())
-          for f in files:
-              if (self.isDir(remoteDir.strip() + "/" + f.strip())):
-                  out += self.removeDir(remoteDir.strip() + "/" + f.strip())
-              else:
-                  out += self.removeFile(remoteDir.strip() + "/" + f.strip())
-          out += self.removeSingleDir(remoteDir.strip())
-      else:
-          out += self.removeFile(remoteDir.strip())
-      return out
-
-  def isDir(self, remotePath):
-      p = self.runCmd(["shell", "ls", "-a", remotePath + '/'])
-
-      data = p.stdout.readlines()
-      if len(data) == 1:
-          res = data[0]
-          if "Not a directory" in res or "No such file or directory" in res:
-              return False
-
-      return True
-
-  def listFiles(self, rootdir):
-      p = self.runCmd(["shell", "ls", "-a", rootdir])
-      data = p.stdout.readlines()
-      data[:] = [item.rstrip('\r\n') for item in data]
-      if (len(data) == 1):
-          if (data[0] == rootdir):
-              return []
-          if (data[0].find("No such file or directory") != -1):
-              return []
-          if (data[0].find("Not a directory") != -1):
-              return []
-          if (data[0].find("Permission denied") != -1):
-              return []
-          if (data[0].find("opendir failed") != -1):
-              return []
-      return data
-
-  # external function
-  # returns:
-  #  success: array of process tuples
-  #  failure: []
-  def getProcessList(self):
-    p = self.runCmd(["shell", "ps"])
-      # first line is the headers
-    p.stdout.readline()
-    proc = p.stdout.readline()
-    ret = []
-    while (proc):
-      els = proc.split()
-      ret.append(list([els[1], els[len(els) - 1], els[0]]))
-      proc =  p.stdout.readline()
-    return ret
-
-  # external function
-  # DEPRECATED: Use shell() or launchApplication() for new code
-  # returns:
-  #  success: pid
-  #  failure: None
-  def fireProcess(self, appname, failIfRunning=False):
-    #strip out env vars
-    parts = appname.split('"');
-    if (len(parts) > 2):
-      parts = parts[2:]
-    return self.launchProcess(parts, failIfRunning)
-
-  # external function
-  # DEPRECATED: Use shell() or launchApplication() for new code
-  # returns:
-  #  success: output filename
-  #  failure: None
-  def launchProcess(self, cmd, outputFile = "process.txt", cwd = '', env = '', failIfRunning=False):
-    if cmd[0] == "am":
-      self.checkCmd(["shell"] + cmd)
-      return outputFile
-
-    acmd = ["shell", "am", "start", "-W"]
-    cmd = ' '.join(cmd).strip()
-    i = cmd.find(" ")
-    # SUT identifies the URL by looking for :\\ -- another strategy to consider
-    re_url = re.compile('^[http|file|chrome|about].*')
-    last = cmd.rfind(" ")
-    uri = ""
-    args = ""
-    if re_url.match(cmd[last:].strip()):
-      args = cmd[i:last].strip()
-      uri = cmd[last:].strip()
-    else:
-      args = cmd[i:].strip()
-    acmd.append("-n")
-    acmd.append(cmd[0:i] + "/.App")
-    if args != "":
-      acmd.append("--es")
-      acmd.append("args")
-      acmd.append(args)
-    if env != '' and env != None:
-      envCnt = 0
-      # env is expected to be a dict of environment variables
-      for envkey, envval in env.iteritems():
-        acmd.append("--es")
-        acmd.append("env" + str(envCnt))
-        acmd.append(envkey + "=" + envval);
-        envCnt += 1
-    if uri != "":
-      acmd.append("-d")
-      acmd.append(''.join(['\'',uri, '\'']));
-    print acmd
-    self.checkCmd(acmd)
-    return outputFile
-
-  # external function
-  # returns:
-  #  success: True
-  #  failure: False
-  def killProcess(self, appname, forceKill=False):
-    procs = self.getProcessList()
-    didKillProcess = False
-    for (pid, name, user) in procs:
-      if name == appname:
-         args = ["shell", "kill"]
-         if forceKill:
-           args.append("-9")
-         args.append(pid)
-         p = self.runCmdAs(args)
-         p.communicate()
-         if p.returncode == 0:
-             didKillProcess = True
-
-    return didKillProcess
-
-  # external function
-  # returns:
-  #  success: filecontents
-  #  failure: None
-  def catFile(self, remoteFile):
-    #p = self.runCmd(["shell", "cat", remoteFile])
-    #return p.stdout.read()
-    return self.getFile(remoteFile)
-
-  # external function
-  # returns:
-  #  success: output of pullfile, string
-  #  failure: None
-  def pullFile(self, remoteFile):
-    #return self.catFile(remoteFile)
-    return self.getFile(remoteFile)
-
-  # copy file from device (remoteFile) to host (localFile)
-  # external function
-  # returns:
-  #  success: output of pullfile, string
-  #  failure: None
-  def getFile(self, remoteFile, localFile = 'tmpfile_dm_adb'):
-    # TODO: add debug flags and allow for printing stdout
-    # self.runCmd(["pull", remoteFile, localFile])
-    try:
-
-      # First attempt to pull file regularly
-      outerr = self.runCmd(["pull",  remoteFile, localFile]).communicate()
-
-      # Now check stderr for errors
-      if outerr[1]:
-        errl = outerr[1].splitlines()
-        if (len(errl) == 1):
-          if (((errl[0].find("Permission denied") != -1)
-            or (errl[0].find("does not exist") != -1))
-            and self.useRunAs):
-            # If we lack permissions to read but have run-as, then we should try
-            # to copy the file to a world-readable location first before attempting
-            # to pull it again.
-            remoteTmpFile = self.getTempDir() + "/" + os.path.basename(remoteFile)
-            self.checkCmdAs(["shell", "dd", "if=" + remoteFile, "of=" + remoteTmpFile])
-            self.checkCmdAs(["shell", "chmod", "777", remoteTmpFile])
-            self.runCmd(["pull",  remoteTmpFile, localFile]).stdout.read()
-            # Clean up temporary file
-            self.checkCmdAs(["shell", "rm", remoteTmpFile])
-
-      f = open(localFile)
-      ret = f.read()
-      f.close()
-      return ret
-    except:
-      return None
-
-  # copy directory structure from device (remoteDir) to host (localDir)
-  # external function
-  # checkDir exists so that we don't create local directories if the
-  # remote directory doesn't exist but also so that we don't call isDir
-  # twice when recursing.
-  # returns:
-  #  success: list of files, string
-  #  failure: None
-  def getDirectory(self, remoteDir, localDir, checkDir=True):
-    ret = []
-    p = self.runCmd(["pull", remoteDir, localDir])
-    p.stdout.readline()
-    line = p.stdout.readline()
-    while (line):
-      els = line.split()
-      f = els[len(els) - 1]
-      i = f.find(localDir)
-      if (i != -1):
-        if (localDir[len(localDir) - 1] != '/'):
-          i = i + 1
-        f = f[i + len(localDir):]
-      i = f.find("/")
-      if (i > 0):
-        f = f[0:i]
-      ret.append(f)
-      line =  p.stdout.readline()
-    #the last line is a summary
-    if (len(ret) > 0):
-      ret.pop()
-    return ret
-
-
-
-  # true/false check if the two files have the same md5 sum
-  # external function
-  # returns:
-  #  success: True
-  #  failure: False
-  def validateFile(self, remoteFile, localFile):
-    return self.getRemoteHash(remoteFile) == self.getLocalHash(localFile)
-
-  # return the md5 sum of a remote file
-  # internal function
-  # returns:
-  #  success: MD5 hash for given filename
-  #  failure: None
-  def getRemoteHash(self, filename):
-    data = self.runCmd(["shell", "ls", "-l", filename]).stdout.read()
-    return data.split()[3]
-
-  def getLocalHash(self, filename):
-    data = subprocess.Popen(["ls", "-l", filename], stdout=subprocess.PIPE).stdout.read()
-    return data.split()[4]
-
-  # Internal method to setup the device root and cache its value
-  def setupDeviceRoot(self):
-    # if self.deviceRoot is already set, create it if necessary, and use it
-    if self.deviceRoot:
-      if not self.dirExists(self.deviceRoot):
-        if not self.mkDir(self.deviceRoot):
-          raise DMError("Unable to create device root %s" % self.deviceRoot)
-      return
-
-    # /mnt/sdcard/tests is preferred to /data/local/tests, but this can be
-    # over-ridden by creating /data/local/tests
-    testRoot = "/data/local/tests"
-    if (self.dirExists(testRoot)):
-      self.deviceRoot = testRoot
-      return
-
-    for (basePath, subPath) in [('/mnt/sdcard', 'tests'),
-                                ('/data/local', 'tests')]:
-      if self.dirExists(basePath):
-        testRoot = os.path.join(basePath, subPath)
-        if self.mkDir(testRoot):
-          self.deviceRoot = testRoot
-          return
-
-    raise DMError("Unable to set up device root as /mnt/sdcard/tests "
-                  "or /data/local/tests")
-
-  # Gets the device root for the testing area on the device
-  # For all devices we will use / type slashes and depend on the device-agent
-  # to sort those out.  The agent will return us the device location where we
-  # should store things, we will then create our /tests structure relative to
-  # that returned path.
-  # Structure on the device is as follows:
-  # /tests
-  #       /<fennec>|<firefox>  --> approot
-  #       /profile
-  #       /xpcshell
-  #       /reftest
-  #       /mochitest
-  #
-  # external function
-  # returns:
-  #  success: path for device root
-  #  failure: None
-  def getDeviceRoot(self):
-    return self.deviceRoot
-
-  # Gets the temporary directory we are using on this device
-  # base on our device root, ensuring also that it exists.
-  #
-  # internal function
-  # returns:
-  #  success: path for temporary directory
-  #  failure: None
-  def getTempDir(self):
-    # Cache result to speed up operations depending
-    # on the temporary directory.
-    if self.tempDir == None:
-      self.tempDir = self.getDeviceRoot() + "/tmp"
-      if (not self.dirExists(self.tempDir)):
-        return self.mkDir(self.tempDir)
-
-    return self.tempDir
-
-  # Either we will have /tests/fennec or /tests/firefox but we will never have
-  # both.  Return the one that exists
-  # TODO: ensure we can support org.mozilla.firefox
-  # external function
-  # returns:
-  #  success: path for app root
-  #  failure: None
-  def getAppRoot(self, packageName):
-    devroot = self.getDeviceRoot()
-    if (devroot == None):
-      return None
-
-    if (packageName and self.dirExists('/data/data/' + packageName)):
-      self.packageName = packageName
-      return '/data/data/' + packageName
-    elif (self.packageName and self.dirExists('/data/data/' + self.packageName)):
-      return '/data/data/' + self.packageName
-
-    # Failure (either not installed or not a recognized platform)
-    print "devicemanagerADB: getAppRoot failed"
-    return None
-
-  # Gets the directory location on the device for a specific test type
-  # Type is one of: xpcshell|reftest|mochitest
-  # external function
-  # returns:
-  #  success: path for test root
-  #  failure: None
-  def getTestRoot(self, type):
-    devroot = self.getDeviceRoot()
-    if (devroot == None):
-      return None
-
-    if (re.search('xpcshell', type, re.I)):
-      self.testRoot = devroot + '/xpcshell'
-    elif (re.search('?(i)reftest', type)):
-      self.testRoot = devroot + '/reftest'
-    elif (re.search('?(i)mochitest', type)):
-      self.testRoot = devroot + '/mochitest'
-    return self.testRoot
-
-
-  # external function
-  # returns:
-  #  success: status from test agent
-  #  failure: None
-  def reboot(self, wait = False):
-    ret = self.runCmd(["reboot"]).stdout.read()
-    if (not wait):
-      return "Success"
-    countdown = 40
-    while (countdown > 0):
-      countdown
-      try:
-        self.checkCmd(["wait-for-device", "shell", "ls", "/sbin"])
-        return ret
-      except:
-        try:
-          self.checkCmd(["root"])
-        except:
-          time.sleep(1)
-          print "couldn't get root"
-    return "Success"
-
-  # external function
-  # returns:
-  #  success: text status from command or callback server
-  #  failure: None
-  def updateApp(self, appBundlePath, processName=None, destPath=None, ipAddr=None, port=30000):
-    return self.runCmd(["install", "-r", appBundlePath]).stdout.read()
-
-  # external function
-  # returns:
-  #  success: time in ms
-  #  failure: None
-  def getCurrentTime(self):
-    timestr = self.runCmd(["shell", "date", "+%s"]).stdout.read().strip()
-    if (not timestr or not timestr.isdigit()):
-        return None
-    return str(int(timestr)*1000)
-
-  # Returns information about the device:
-  # Directive indicates the information you want to get, your choices are:
-  # os - name of the os
-  # id - unique id of the device
-  # uptime - uptime of the device
-  # systime - system time of the device
-  # screen - screen resolution
-  # memory - memory stats
-  # process - list of running processes (same as ps)
-  # disk - total, free, available bytes on disk
-  # power - power status (charge, battery temp)
-  # all - all of them - or call it with no parameters to get all the information
-  ### Note that uptimemillis is NOT supported, as there is no way to get this
-  ### data from the shell.
-  # returns:
-  #   success: dict of info strings by directive name
-  #   failure: {}
-  def getInfo(self, directive="all"):
-    ret = {}
-    if (directive == "id" or directive == "all"):
-      ret["id"] = self.runCmd(["get-serialno"]).stdout.read()
-    if (directive == "os" or directive == "all"):
-      ret["os"] = self.runCmd(["shell", "getprop", "ro.build.display.id"]).stdout.read()
-    if (directive == "uptime" or directive == "all"):
-      utime = self.runCmd(["shell", "uptime"]).stdout.read()
-      if (not utime):
-        raise DMError("error getting uptime")
-      utime = utime[9:]
-      hours = utime[0:utime.find(":")]
-      utime = utime[utime[1:].find(":") + 2:]
-      minutes = utime[0:utime.find(":")]
-      utime = utime[utime[1:].find(":") +  2:]
-      seconds = utime[0:utime.find(",")]
-      ret["uptime"] = ["0 days " + hours + " hours " + minutes + " minutes " + seconds + " seconds"]
-    if (directive == "process" or directive == "all"):
-      ret["process"] = self.runCmd(["shell", "ps"]).stdout.read()
-    if (directive == "systime" or directive == "all"):
-      ret["systime"] = self.runCmd(["shell", "date"]).stdout.read()
-    print ret
-    return ret
-
-  def runCmd(self, args):
-    # If we are not root but have run-as, and we're trying to execute
-    # a shell command then using run-as is the best we can do
-    finalArgs = [self.adbPath]
-    if self.deviceSerial:
-      finalArgs.extend(['-s', self.deviceSerial])
-    if (not self.haveRoot and self.useRunAs and args[0] == "shell" and args[1] != "run-as"):
-      args.insert(1, "run-as")
-      args.insert(2, self.packageName)
-    finalArgs.extend(args)
-    return subprocess.Popen(finalArgs, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
-
-  def runCmdAs(self, args):
-    if self.useRunAs:
-      args.insert(1, "run-as")
-      args.insert(2, self.packageName)
-    return self.runCmd(args)
-
-  # timeout is specified in seconds, and if no timeout is given, 
-  # we will run until the script returns
-  def checkCmd(self, args, timeout=None):
-    # If we are not root but have run-as, and we're trying to execute
-    # a shell command then using run-as is the best we can do
-    finalArgs = [self.adbPath]
-    if self.deviceSerial:
-      finalArgs.extend(['-s', self.deviceSerial])
-    if (not self.haveRoot and self.useRunAs and args[0] == "shell" and args[1] != "run-as"):
-      args.insert(1, "run-as")
-      args.insert(2, self.packageName)
-    finalArgs.extend(args)
-    if timeout:
-        timeout = int(timeout)
-        proc = subprocess.Popen(finalArgs)
-        start_time = time.time()
-        ret_code = proc.poll()
-        while ((time.time() - start_time) <= timeout) and ret_code == None:
-            time.sleep(1)
-            ret_code = proc.poll()
-        if ret_code == None:
-            proc.kill()
-            raise DMError("Timeout exceeded for checkCmd call")
-        return ret_code
-    return subprocess.check_call(finalArgs)
-
-  def checkCmdAs(self, args, timeout=None):
-    if (self.useRunAs):
-      args.insert(1, "run-as")
-      args.insert(2, self.packageName)
-    return self.checkCmd(args, timeout)
-
-  # external function
-  # returns:
-  #  success: True
-  #  failure: False
-  def chmodDir(self, remoteDir):
-    if (self.isDir(remoteDir)):
-      files = self.listFiles(remoteDir.strip())
-      for f in files:
-        remoteEntry = remoteDir.strip() + "/" + f.strip()
-        if (self.isDir(remoteEntry)):
-          self.chmodDir(remoteEntry)
-        else:
-          self.checkCmdAs(["shell", "chmod", "777", remoteEntry])
-          print "chmod " + remoteEntry
-      self.checkCmdAs(["shell", "chmod", "777", remoteDir])
-      print "chmod " + remoteDir
-    else:
-      self.checkCmdAs(["shell", "chmod", "777", remoteDir.strip()])
-      print "chmod " + remoteDir.strip()
-    return True
-
-  def verifyADB(self):
-    # Check to see if adb itself can be executed.
-    if self.adbPath != 'adb':
-      if not os.access(self.adbPath, os.X_OK):
-        raise DMError("invalid adb path, or adb not executable: %s", self.adbPath)
-
-    try:
-      self.checkCmd(["version"])
-    except os.error, err:
-      raise DMError("unable to execute ADB (%s): ensure Android SDK is installed and adb is in your $PATH" % err)
-    except subprocess.CalledProcessError:
-      raise DMError("unable to execute ADB: ensure Android SDK is installed and adb is in your $PATH")
-
-  def verifyDevice(self):
-    # If there is a device serial number, see if adb is connected to it
-    if self.deviceSerial:
-      deviceStatus = None
-      proc = subprocess.Popen([self.adbPath, "devices"],
-                              stdout=subprocess.PIPE,
-                              stderr=subprocess.STDOUT)
-      for line in proc.stdout:
-        m = re.match('(.+)?\s+(.+)$', line)
-        if m:
-          if self.deviceSerial == m.group(1):
-            deviceStatus = m.group(2)
-      if deviceStatus == None:
-        raise DMError("device not found: %s" % self.deviceSerial)
-      elif deviceStatus != "device":
-        raise DMError("bad status for device %s: %s" % (self.deviceSerial,
-                                                        deviceStatus))
-
-    # Check to see if we can connect to device and run a simple command
-    try:
-      self.checkCmd(["shell", "echo"])
-    except subprocess.CalledProcessError:
-      raise DMError("unable to connect to device: is it plugged in?")
-
-  def verifyRoot(self):
-    # a test to see if we have root privs
-    p = self.runCmd(["shell", "id"])
-    response = p.stdout.readline()
-    response = response.rstrip()
-    response = response.split(' ')
-    if (response[0].find('uid=0') < 0 or response[1].find('gid=0') < 0):
-      print "NOT running as root ", response[0].find('uid=0')
-      raise DMError("not running as root")
-
-    self.haveRoot = True
-
-  def isCpAvailable(self):
-    # Some Android systems may not have a cp command installed,
-    # or it may not be executable by the user.
-    data = self.runCmd(["shell", "cp"]).stdout.read()
-    if (re.search('Usage', data)):
-      return True
-    else:
-      data = self.runCmd(["shell", "dd", "-"]).stdout.read()
-      if (re.search('unknown operand', data)):
-        print "'cp' not found, but 'dd' was found as a replacement"
-        self.useDDCopy = True
-        return True
-      print "unable to execute 'cp' on device; consider installing busybox from Android Market"
-      return False
-
-  def verifyRunAs(self):
-    # If a valid package name is available, and certain other
-    # conditions are met, devicemanagerADB can execute file operations
-    # via the "run-as" command, so that pushed files and directories 
-    # are created by the uid associated with the package, more closely
-    # echoing conditions encountered by Fennec at run time.
-    # Check to see if run-as can be used here, by verifying a 
-    # file copy via run-as.
-    self.useRunAs = False
-    devroot = self.getDeviceRoot()
-    if (self.packageName and self.isCpAvailable() and devroot):
-      tmpDir = self.getTempDir()
-
-      # The problem here is that run-as doesn't cause a non-zero exit code
-      # when failing because of a non-existent or non-debuggable package :(
-      runAsOut = self.runCmd(["shell", "run-as", self.packageName, "mkdir", devroot + "/sanity"]).communicate()[0]
-      if runAsOut.startswith("run-as:") and ("not debuggable" in runAsOut or
-                                             "is unknown" in runAsOut):
-        raise DMError("run-as failed sanity check")
-
-      tmpfile = tempfile.NamedTemporaryFile()
-      self.checkCmd(["push", tmpfile.name, tmpDir + "/tmpfile"])
-      if self.useDDCopy:
-        self.checkCmd(["shell", "run-as", self.packageName, "dd", "if=" + tmpDir + "/tmpfile", "of=" + devroot + "/sanity/tmpfile"])
-      else:
-        self.checkCmd(["shell", "run-as", self.packageName, "cp", tmpDir + "/tmpfile", devroot + "/sanity"])
-      if (self.fileExists(devroot + "/sanity/tmpfile")):
-        print "will execute commands via run-as " + self.packageName
-        self.useRunAs = True
-      self.checkCmd(["shell", "rm", devroot + "/tmp/tmpfile"])
-      self.checkCmd(["shell", "run-as", self.packageName, "rm", "-r", devroot + "/sanity"])
-
-  def isUnzipAvailable(self):
-    data = self.runCmdAs(["shell", "unzip"]).stdout.read()
-    if (re.search('Usage', data)):
-      return True
-    else:
-      return False
-
-  def isLocalZipAvailable(self):
-    try:
-      subprocess.check_call(["zip", "-?"], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
-    except:
-      return False
-    return True
-
-  def verifyZip(self):
-    # If "zip" can be run locally, and "unzip" can be run remotely, then pushDir
-    # can use these to push just one file per directory -- a significant
-    # optimization for large directories.
-    self.useZip = False
-    if (self.isUnzipAvailable() and self.isLocalZipAvailable()):
-      print "will use zip to push directories"
-      self.useZip = True
-    else:
-      raise DMError("zip not available")
deleted file mode 100644
--- a/build/mobile/devicemanagerSUT.py
+++ /dev/null
@@ -1,1240 +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/.
-
-import select
-import socket
-import SocketServer
-import time
-import os
-import re
-import posixpath
-import subprocess
-from threading import Thread
-import StringIO
-from devicemanager import DeviceManager, FileError, NetworkTools, _pop_last_line
-import errno
-from distutils.version import StrictVersion
-
-class AgentError(Exception):
-  "SUTAgent-specific exception."
-
-  def __init__(self, msg= '', fatal = False):
-    self.msg = msg
-    self.fatal = fatal
-
-  def __str__(self):
-    return self.msg
-
-class DeviceManagerSUT(DeviceManager):
-  host = ''
-  port = 0
-  debug = 2
-  retries = 0
-  tempRoot = os.getcwd()
-  base_prompt = '$>'
-  base_prompt_re = '\$\>'
-  prompt_sep = '\x00'
-  prompt_regex = '.*(' + base_prompt_re + prompt_sep + ')'
-  agentErrorRE = re.compile('^##AGENT-WARNING##\ ?(.*)')
-
-  # TODO: member variable to indicate error conditions.
-  # This should be set to a standard error from the errno module.
-  # So, for example, when an error occurs because of a missing file/directory,
-  # before returning, the function would do something like 'self.error = errno.ENOENT'.
-  # The error would be set where appropriate--so sendCMD() could set socket errors,
-  # pushFile() and other file-related commands could set filesystem errors, etc.
-
-  def __init__(self, host, port = 20701, retrylimit = 5, deviceRoot = None):
-    self.host = host
-    self.port = port
-    self.retrylimit = retrylimit
-    self.retries = 0
-    self._sock = None
-    self.deviceRoot = deviceRoot
-    if self.getDeviceRoot() == None:
-      raise BaseException("Failed to connect to SUT Agent and retrieve the device root.")
-    try:
-      verstring = self.runCmds([{ 'cmd': 'ver' }])
-      self.agentVersion = re.sub('SUTAgentAndroid Version ', '', verstring)
-    except AgentError, err:
-      raise BaseException("Failed to get SUTAgent version")
-
-  def _cmdNeedsResponse(self, cmd):
-    """ Not all commands need a response from the agent:
-        * rebt obviously doesn't get a response
-        * uninstall performs a reboot to ensure starting in a clean state and
-          so also doesn't look for a response
-    """
-    noResponseCmds = [re.compile('^rebt'),
-                      re.compile('^uninst .*$'),
-                      re.compile('^pull .*$')]
-
-    for c in noResponseCmds:
-      if (c.match(cmd)):
-        return False
-
-    # If the command is not in our list, then it gets a response
-    return True
-
-  def _stripPrompt(self, data):
-    '''
-    internal function
-    take a data blob and strip instances of the prompt '$>\x00'
-    '''
-    promptre = re.compile(self.prompt_regex + '.*')
-    retVal = []
-    lines = data.split('\n')
-    for line in lines:
-      foundPrompt = False
-      try:
-        while (promptre.match(line)):
-          foundPrompt = True
-          pieces = line.split(self.prompt_sep)
-          index = pieces.index('$>')
-          pieces.pop(index)
-          line = self.prompt_sep.join(pieces)
-      except(ValueError):
-        pass
-
-      # we don't want to append lines that are blank after stripping the
-      # prompt (those are basically "prompts")
-      if not foundPrompt or line:
-        retVal.append(line)
-
-    return '\n'.join(retVal)
-
-  def _shouldCmdCloseSocket(self, cmd):
-    """ Some commands need to close the socket after they are sent:
-    * rebt
-    * uninst
-    * quit
-    """
-    socketClosingCmds = [re.compile('^quit.*'),
-                         re.compile('^rebt.*'),
-                         re.compile('^uninst .*$')]
-
-    for c in socketClosingCmds:
-      if (c.match(cmd)):
-        return True
-
-    return False
-
-  def sendCmds(self, cmdlist, outputfile, timeout = None):
-    '''
-    a wrapper for _doCmds that loops up to self.retrylimit iterations.
-    this allows us to move the retry logic outside of the _doCmds() to make it
-    easier for debugging in the future.
-    note that since cmdlist is a list of commands, they will all be retried if
-    one fails.  this is necessary in particular for pushFile(), where we don't want
-    to accidentally send extra data if a failure occurs during data transmission.
-    '''
-    if timeout:
-      raise NotImplementedError("'timeout' parameter is not yet supported")
-    while self.retries < self.retrylimit:
-      try:
-        self._doCmds(cmdlist, outputfile, timeout)
-        return
-      except AgentError, err:
-        # re-raise error if it's fatal (i.e. the device got the command but
-        # couldn't execute it). retry otherwise
-        if err.fatal:
-          raise err
-        if self.debug >= 2:
-          print err
-        self.retries += 1
-
-    raise AgentError("unable to connect to %s after %s attempts" % (self.host, self.retrylimit))
-
-  def runCmds(self, cmdlist, timeout = None):
-    '''
-    similar to sendCmds, but just returns any output as a string instead of
-    writing to a file. this is normally what you want to call to send a set
-    of commands to the agent
-    '''
-    outputfile = StringIO.StringIO()
-    self.sendCmds(cmdlist, outputfile, timeout)
-    outputfile.seek(0)
-    return outputfile.read()
-
-  def _doCmds(self, cmdlist, outputfile, timeout):
-    promptre = re.compile(self.prompt_regex + '$')
-    shouldCloseSocket = False
-    recvGuard = 1000
-
-    if not self._sock:
-      try:
-        if self.debug >= 1:
-          print "reconnecting socket"
-        self._sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
-      except socket.error, msg:
-        self._sock = None
-        raise AgentError("unable to create socket: "+str(msg))
-
-      try:
-        self._sock.connect((self.host, int(self.port)))
-        self._sock.recv(1024)
-      except socket.error, msg:
-        self._sock.close()
-        self._sock = None
-        raise AgentError("unable to connect socket: "+str(msg))
-
-    for cmd in cmdlist:
-      cmdline = '%s\r\n' % cmd['cmd']
-
-      try:
-        sent = self._sock.send(cmdline)
-        if sent != len(cmdline):
-          raise AgentError("ERROR: our cmd was %s bytes and we "
-                           "only sent %s" % (len(cmdline), sent))
-        if cmd.get('data'):
-          sent = self._sock.send(cmd['data'])
-          if sent != len(cmd['data']):
-              raise AgentError("ERROR: we had %s bytes of data to send, but "
-                               "only sent %s" % (len(cmd['data']), sent))
-
-        if (self.debug >= 4): print "sent cmd: " + str(cmd['cmd'])
-      except socket.error, msg:
-        self._sock.close()
-        self._sock = None
-        if self.debug >= 1:
-          print "Error sending data to socket. cmd="+str(cmd['cmd'])+"; err="+str(msg)
-        return False
-
-      # Check if the command should close the socket
-      shouldCloseSocket = self._shouldCmdCloseSocket(cmd['cmd'])
-
-      # Handle responses from commands
-      if (self._cmdNeedsResponse(cmd['cmd'])):
-        found = False
-        loopguard = 0
-        data = ""
-
-        while (found == False and (loopguard < recvGuard)):
-          temp = ''
-          if (self.debug >= 4): print "recv'ing..."
-
-          # Get our response
-          try:
-             # Wait up to a second for socket to become ready for reading...
-            if select.select([self._sock], [], [], 1)[0]:
-                temp = self._sock.recv(1024)
-            if (self.debug >= 4): print "response: " + str(temp)
-          except socket.error, err:
-            self._sock.close()
-            self._sock = None
-            # This error shows up with we have our tegra rebooted.
-            if err[0] == errno.ECONNRESET:
-              raise AgentError("Automation error: Error receiving data from socket (possible reboot). cmd=%s; err=%s" % (cmd, err))
-            raise AgentError("Error receiving data from socket. cmd=%s; err=%s" % (cmd, err))
-
-          data += temp
-
-          # If something goes wrong in the agent it will send back a string that
-          # starts with '##AGENT-WARNING##'
-          errorMatch = self.agentErrorRE.match(data)
-          if errorMatch:
-            raise AgentError("Agent Error processing command '%s'; err='%s'" %
-                             (cmd['cmd'], errorMatch.group(1)), fatal=True)
-
-          for line in data.splitlines():
-            if promptre.match(line):
-              found = True
-              data = self._stripPrompt(data)
-              break
-
-          # periodically flush data to output file to make sure it doesn't get
-          # too big/unwieldly
-          if len(data) > 1024:
-              outputfile.write(data[0:1024])
-              data = data[1024:]
-
-          # If we violently lose the connection to the device, this loop tends to spin,
-          # this guard prevents that
-          if (temp == ''):
-            loopguard += 1
-
-        # Write any remaining data to outputfile
-        outputfile.write(data)
-
-    if shouldCloseSocket:
-      try:
-        self._sock.close()
-        self._sock = None
-      except:
-        self._sock = None
-        raise AgentError("Error closing socket")
-
-  # external function: executes shell command on device
-  # returns:
-  # success: <return code>
-  # failure: None
-  def shell(self, cmd, outputfile, env=None, cwd=None, timeout=None, root=False):
-    cmdline = self._escapedCommandLine(cmd)
-    if env:
-      cmdline = '%s %s' % (self.formatEnvString(env), cmdline)
-
-    haveExecSu = (StrictVersion(self.agentVersion) >= StrictVersion('1.13'))
-
-    # Depending on agent version we send one of the following commands here:
-    # * exec (run as normal user)
-    # * execsu (run as privileged user)
-    # * execcwd (run as normal user from specified directory)
-    # * execcwdsu (run as privileged user from specified directory)
-
-    cmd = "exec"
-    if cwd:
-      cmd += "cwd"
-    if root and haveExecSu:
-      cmd += "su"
-
-    try:
-      if cwd:
-        self.sendCmds([{ 'cmd': '%s %s %s' % (cmd, cwd, cmdline) }], outputfile, timeout)
-      else:
-        if (not root) or haveExecSu:
-          self.sendCmds([{ 'cmd': '%s %s' % (cmd, cmdline) }], outputfile, timeout)
-        else:
-          # need to manually inject su -c for backwards compatibility (this may
-          # not work on ICS or above!!)
-          # (FIXME: this backwards compatibility code is really ugly and should
-          # be deprecated at some point in the future)
-          self.sendCmds([ { 'cmd': '%s su -c "%s"' % (cmd, cmdline) }], outputfile,
-                          timeout)
-    except AgentError:
-      return None
-
-    # dig through the output to get the return code
-    lastline = _pop_last_line(outputfile)
-    if lastline:
-      m = re.search('return code \[([0-9]+)\]', lastline)
-      if m:
-        return int(m.group(1))
-
-    # woops, we couldn't find an end of line/return value
-    return None
-
-  # external function
-  # returns:
-  #  success: True
-  #  failure: False
-  def pushFile(self, localname, destname):
-    if (os.name == "nt"):
-      destname = destname.replace('\\', '/')
-
-    if (self.debug >= 3): print "in push file with: " + localname + ", and: " + destname
-    if (self.dirExists(destname)):
-      if (not destname.endswith('/')):
-        destname = destname + '/'
-      destname = destname + os.path.basename(localname)
-    if (self.validateFile(destname, localname) == True):
-      if (self.debug >= 3): print "files are validated"
-      return True
-
-    if self.mkDirs(destname) == None:
-      print "unable to make dirs: " + destname
-      return False
-
-    if (self.debug >= 3): print "sending: push " + destname
-
-    filesize = os.path.getsize(localname)
-    f = open(localname, 'rb')
-    data = f.read()
-    f.close()
-
-    try:
-      retVal = self.runCmds([{ 'cmd': 'push ' + destname + ' ' + str(filesize),
-                               'data': data }])
-    except AgentError, e:
-      print "error pushing file: %s" % e.msg
-      return False
-
-    if (self.debug >= 3): print "push returned: " + str(retVal)
-
-    validated = False
-    if (retVal):
-      retline = retVal.strip()
-      if (retline == None):
-        # Then we failed to get back a hash from agent, try manual validation
-        validated = self.validateFile(destname, localname)
-      else:
-        # Then we obtained a hash from push
-        localHash = self.getLocalHash(localname)
-        if (str(localHash) == str(retline)):
-          validated = True
-    else:
-      # We got nothing back from sendCMD, try manual validation
-      validated = self.validateFile(destname, localname)
-
-    if (validated):
-      if (self.debug >= 3): print "Push File Validated!"
-      return True
-    else:
-      if (self.debug >= 2): print "Push File Failed to Validate!"
-      return False
-
-  # external function
-  # returns:
-  #  success: directory name
-  #  failure: None
-  def mkDir(self, name):
-    if (self.dirExists(name)):
-      return name
-    else:
-      try:
-        retVal = self.runCmds([{ 'cmd': 'mkdr ' + name }])
-      except AgentError:
-        retVal = None
-      return retVal
-
-  # push localDir from host to remoteDir on the device
-  # external function
-  # returns:
-  #  success: remoteDir
-  #  failure: None
-  def pushDir(self, localDir, remoteDir):
-    if (self.debug >= 2): print "pushing directory: %s to %s" % (localDir, remoteDir)
-    for root, dirs, files in os.walk(localDir, followlinks=True):
-      parts = root.split(localDir)
-      for file in files:
-        remoteRoot = remoteDir + '/' + parts[1]
-        if (remoteRoot.endswith('/')):
-          remoteName = remoteRoot + file
-        else:
-          remoteName = remoteRoot + '/' + file
-        if (parts[1] == ""): remoteRoot = remoteDir
-        if (self.pushFile(os.path.join(root, file), remoteName) == False):
-          # retry once
-          self.removeFile(remoteName)
-          if (self.pushFile(os.path.join(root, file), remoteName) == False):
-            return None
-    return remoteDir
-
-  # external function
-  # returns:
-  #  success: True
-  #  failure: False
-  def dirExists(self, dirname):
-    match = ".*" + dirname.replace('^', '\^') + "$"
-    dirre = re.compile(match)
-    try:
-      data = self.runCmds([ { 'cmd': 'cd ' + dirname }, { 'cmd': 'cwd' }])
-    except AgentError:
-      return False
-
-    found = False
-    for d in data.splitlines():
-      if (dirre.match(d)):
-        found = True
-
-    return found
-
-  # Because we always have / style paths we make this a lot easier with some
-  # assumptions
-  # external function
-  # returns:
-  #  success: True
-  #  failure: False
-  def fileExists(self, filepath):
-    s = filepath.split('/')
-    containingpath = '/'.join(s[:-1])
-    listfiles = self.listFiles(containingpath)
-    for f in listfiles:
-      if (f == s[-1]):
-        return True
-    return False
-
-  # list files on the device, requires cd to directory first
-  # external function
-  # returns:
-  #  success: array of filenames, ['file1', 'file2', ...]
-  #  failure: []
-  def listFiles(self, rootdir):
-    rootdir = rootdir.rstrip('/')
-    if (self.dirExists(rootdir) == False):
-      return []
-    try:
-      data = self.runCmds([{ 'cmd': 'cd ' + rootdir }, { 'cmd': 'ls' }])
-    except AgentError:
-      return []
-
-    files = filter(lambda x: x, data.splitlines())
-    if len(files) == 1 and files[0] == '<empty>':
-      # special case on the agent: empty directories return just the string "<empty>"
-      return []
-    return files
-
-  # external function
-  # returns:
-  #  success: output of telnet, i.e. "removing file: /mnt/sdcard/tests/test.txt"
-  #  failure: None
-  def removeFile(self, filename):
-    if (self.debug>= 2): print "removing file: " + filename
-    try:
-      retVal = self.runCmds([{ 'cmd': 'rm ' + filename }])
-    except AgentError:
-      return None
-
-    return retVal
-
-  # does a recursive delete of directory on the device: rm -Rf remoteDir
-  # external function
-  # returns:
-  #  success: output of telnet, i.e. "removing file: /mnt/sdcard/tests/test.txt"
-  #  failure: None
-  def removeDir(self, remoteDir):
-    try:
-      retVal = self.runCmds([{ 'cmd': 'rmdr ' + remoteDir }])
-    except AgentError:
-      return None
-
-    return retVal
-
-  # external function
-  # returns:
-  #  success: array of process tuples
-  #  failure: []
-  def getProcessList(self):
-    try:
-      data = self.runCmds([{ 'cmd': 'ps' }])
-    except AgentError:
-      return []
-
-    files = []
-    for line in data.splitlines():
-      if line:
-        pidproc = line.strip().split()
-        if (len(pidproc) == 2):
-          files += [[pidproc[0], pidproc[1]]]
-        elif (len(pidproc) == 3):
-          #android returns <userID> <procID> <procName>
-          files += [[pidproc[1], pidproc[2], pidproc[0]]]
-    return files
-
-  # external function
-  # DEPRECATED: Use shell() or launchApplication() for new code
-  # returns:
-  #  success: pid
-  #  failure: None
-  def fireProcess(self, appname, failIfRunning=False):
-    if (not appname):
-      if (self.debug >= 1): print "WARNING: fireProcess called with no command to run"
-      return None
-
-    if (self.debug >= 2): print "FIRE PROC: '" + appname + "'"
-
-    if (self.processExist(appname) != None):
-      print "WARNING: process %s appears to be running already\n" % appname
-      if (failIfRunning):
-        return None
-
-    try:
-      self.runCmds([{ 'cmd': 'exec ' + appname }])
-    except AgentError:
-      return None
-
-    # The 'exec' command may wait for the process to start and end, so checking
-    # for the process here may result in process = None.
-    process = self.processExist(appname)
-    if (self.debug >= 4): print "got pid: %s for process: %s" % (process, appname)
-
-    return process
-
-  # external function
-  # DEPRECATED: Use shell() or launchApplication() for new code
-  # returns:
-  #  success: output filename
-  #  failure: None
-  def launchProcess(self, cmd, outputFile = "process.txt", cwd = '', env = '', failIfRunning=False):
-    if not cmd:
-      if (self.debug >= 1): print "WARNING: launchProcess called without command to run"
-      return None
-
-    cmdline = subprocess.list2cmdline(cmd)
-    if (outputFile == "process.txt" or outputFile == None):
-      outputFile = self.getDeviceRoot();
-      if outputFile is None:
-        return None
-      outputFile += "/process.txt"
-      cmdline += " > " + outputFile
-
-    # Prepend our env to the command
-    cmdline = '%s %s' % (self.formatEnvString(env), cmdline)
-
-    if self.fireProcess(cmdline, failIfRunning) is None:
-      return None
-    return outputFile
-
-  # external function
-  # returns:
-  #  success: True
-  #  failure: False
-  def killProcess(self, appname, forceKill=False):
-    if forceKill:
-      print "WARNING: killProcess(): forceKill parameter unsupported on SUT"
-    try:
-      self.runCmds([{ 'cmd': 'kill ' + appname }])
-    except AgentError:
-      return False
-
-    return True
-
-  # external function
-  # returns:
-  #  success: tmpdir, string
-  #  failure: None
-  def getTempDir(self):
-    try:
-      data = self.runCmds([{ 'cmd': 'tmpd' }])
-    except AgentError:
-      return None
-
-    return data.strip()
-
-  # external function
-  # returns:
-  #  success: filecontents
-  #  failure: None
-  def catFile(self, remoteFile):
-    try:
-      data = self.runCmds([{ 'cmd': 'cat ' + remoteFile }])
-    except AgentError:
-      return None
-
-    return data
-
-  # external function
-  # returns:
-  #  success: output of pullfile, string
-  #  failure: None
-  def pullFile(self, remoteFile):
-    """Returns contents of remoteFile using the "pull" command.
-    The "pull" command is different from other commands in that DeviceManager
-    has to read a certain number of bytes instead of just reading to the
-    next prompt.  This is more robust than the "cat" command, which will be
-    confused if the prompt string exists within the file being catted.
-    However it means we can't use the response-handling logic in sendCMD().
-    """
-
-    def err(error_msg):
-        err_str = 'error returned from pull: %s' % error_msg
-        print err_str
-        self._sock = None
-        raise FileError(err_str)
-
-    # FIXME: We could possibly move these socket-reading functions up to
-    # the class level if we wanted to refactor sendCMD().  For now they are
-    # only used to pull files.
-
-    def uread(to_recv, error_msg):
-      """ unbuffered read """
-      try:
-        data = self._sock.recv(to_recv)
-        if not data:
-          err(error_msg)
-          return None
-        return data
-      except:
-        err(error_msg)
-        return None
-
-    def read_until_char(c, buffer, error_msg):
-      """ read until 'c' is found; buffer rest """
-      while not '\n' in buffer:
-        data = uread(1024, error_msg)
-        if data == None:
-          err(error_msg)
-          return ('', '', '')
-        buffer += data
-      return buffer.partition(c)
-
-    def read_exact(total_to_recv, buffer, error_msg):
-      """ read exact number of 'total_to_recv' bytes """
-      while len(buffer) < total_to_recv:
-        to_recv = min(total_to_recv - len(buffer), 1024)
-        data = uread(to_recv, error_msg)
-        if data == None:
-          return None
-        buffer += data
-      return buffer
-
-    prompt = self.base_prompt + self.prompt_sep
-    buffer = ''
-
-    # expected return value:
-    # <filename>,<filesize>\n<filedata>
-    # or, if error,
-    # <filename>,-1\n<error message>
-    try:
-      # just send the command first, we read the response inline below
-      self.runCmds([{ 'cmd': 'pull ' + remoteFile }])
-    except AgentError:
-      return None
-
-    # read metadata; buffer the rest
-    metadata, sep, buffer = read_until_char('\n', buffer, 'could not find metadata')
-    if not metadata:
-      return None
-    if self.debug >= 3:
-      print 'metadata: %s' % metadata
-
-    filename, sep, filesizestr = metadata.partition(',')
-    if sep == '':
-      err('could not find file size in returned metadata')
-      return None
-    try:
-        filesize = int(filesizestr)
-    except ValueError:
-      err('invalid file size in returned metadata')
-      return None
-
-    if filesize == -1:
-      # read error message
-      error_str, sep, buffer = read_until_char('\n', buffer, 'could not find error message')
-      if not error_str:
-        return None
-      # prompt should follow
-      read_exact(len(prompt), buffer, 'could not find prompt')
-      print "DeviceManager: error pulling file '%s': %s" % (remoteFile, error_str)
-      return None
-
-    # read file data
-    total_to_recv = filesize + len(prompt)
-    buffer = read_exact(total_to_recv, buffer, 'could not get all file data')
-    if buffer == None:
-      return None
-    if buffer[-len(prompt):] != prompt:
-      err('no prompt found after file data--DeviceManager may be out of sync with agent')
-      return buffer
-    return buffer[:-len(prompt)]
-
-  # copy file from device (remoteFile) to host (localFile)
-  # external function
-  # returns:
-  #  success: output of pullfile, string
-  #  failure: None
-  def getFile(self, remoteFile, localFile = ''):
-    if localFile == '':
-      localFile = os.path.join(self.tempRoot, "temp.txt")
-
-    try:
-      retVal = self.pullFile(remoteFile)
-    except:
-      return None
-
-    if (retVal is None):
-      return None
-
-    fhandle = open(localFile, 'wb')
-    fhandle.write(retVal)
-    fhandle.close()
-    if not self.validateFile(remoteFile, localFile):
-      print 'failed to validate file when downloading %s!' % remoteFile
-      return None
-    return retVal
-
-  # copy directory structure from device (remoteDir) to host (localDir)
-  # external function
-  # checkDir exists so that we don't create local directories if the
-  # remote directory doesn't exist but also so that we don't call isDir
-  # twice when recursing.
-  # returns:
-  #  success: list of files, string
-  #  failure: None
-  def getDirectory(self, remoteDir, localDir, checkDir=True):
-    if (self.debug >= 2): print "getting files in '" + remoteDir + "'"
-    if checkDir:
-      try:
-        is_dir = self.isDir(remoteDir)
-      except FileError:
-        return None
-      if not is_dir:
-        return None
-
-    filelist = self.listFiles(remoteDir)
-    if (self.debug >= 3): print filelist
-    if not os.path.exists(localDir):
-      os.makedirs(localDir)
-
-    for f in filelist:
-      if f == '.' or f == '..':
-        continue
-      remotePath = remoteDir + '/' + f
-      localPath = os.path.join(localDir, f)
-      try:
-        is_dir = self.isDir(remotePath)
-      except FileError:
-        print 'isdir failed on file "%s"; continuing anyway...' % remotePath
-        continue
-      if is_dir:
-        if (self.getDirectory(remotePath, localPath, False) == None):
-          print 'failed to get directory "%s"' % remotePath
-          return None
-      else:
-        # It's sometimes acceptable to have getFile() return None, such as
-        # when the agent encounters broken symlinks.
-        # FIXME: This should be improved so we know when a file transfer really
-        # failed.
-        if self.getFile(remotePath, localPath) == None:
-          print 'failed to get file "%s"; continuing anyway...' % remotePath
-    return filelist
-
-  # external function
-  # returns:
-  #  success: True
-  #  failure: False
-  #  Throws a FileError exception when null (invalid dir/filename)
-  def isDir(self, remotePath):
-    try:
-      data = self.runCmds([{ 'cmd': 'isdir ' + remotePath }])
-    except AgentError:
-      # normally there should be no error here; a nonexistent file/directory will
-      # return the string "<filename>: No such file or directory".
-      # However, I've seen AGENT-WARNING returned before.
-      return False
-
-    retVal = data.strip()
-    if not retVal:
-      raise FileError('isdir returned null')
-    return retVal == 'TRUE'
-
-  # true/false check if the two files have the same md5 sum
-  # external function
-  # returns:
-  #  success: True
-  #  failure: False
-  def validateFile(self, remoteFile, localFile):
-    remoteHash = self.getRemoteHash(remoteFile)
-    localHash = self.getLocalHash(localFile)
-
-    if (remoteHash == None):
-      return False
-
-    if (remoteHash == localHash):
-      return True
-
-    return False
-
-  # return the md5 sum of a remote file
-  # internal function
-  # returns:
-  #  success: MD5 hash for given filename
-  #  failure: None
-  def getRemoteHash(self, filename):
-    try:
-      data = self.runCmds([{ 'cmd': 'hash ' + filename }])
-    except AgentError:
-      return None
-
-    retVal = None
-    if data:
-      retVal = data.strip()
-    if self.debug >= 3:
-      print "remote hash returned: '%s'" % retVal
-    return retVal
-
-  # Gets the device root for the testing area on the device
-  # For all devices we will use / type slashes and depend on the device-agent
-  # to sort those out.  The agent will return us the device location where we
-  # should store things, we will then create our /tests structure relative to
-  # that returned path.
-  # Structure on the device is as follows:
-  # /tests
-  #       /<fennec>|<firefox>  --> approot
-  #       /profile
-  #       /xpcshell
-  #       /reftest
-  #       /mochitest
-  #
-  # external function
-  # returns:
-  #  success: path for device root
-  #  failure: None
-  def getDeviceRoot(self):
-    if self.deviceRoot:
-      deviceRoot = self.deviceRoot
-    else:
-      try:
-        data = self.runCmds([{ 'cmd': 'testroot' }])
-      except:
-        return None
-
-      deviceRoot = data.strip() + '/tests'
-
-    if (not self.dirExists(deviceRoot)):
-      if (self.mkDir(deviceRoot) == None):
-        return None
-
-    self.deviceRoot = deviceRoot
-    return self.deviceRoot
-
-  def getAppRoot(self, packageName):
-    try:
-      data = self.runCmds([{ 'cmd': 'getapproot '+packageName }])
-    except:
-      return None
-
-    return data.strip()
-
-  # external function
-  # returns:
-  #  success: output of unzip command
-  #  failure: None
-  def unpackFile(self, file_path, dest_dir=None):
-    devroot = self.getDeviceRoot()
-    if (devroot == None):
-      return None
-
-    # if no dest_dir is passed in just set it to file_path's folder
-    if not dest_dir:
-      dest_dir = posixpath.dirname(file_path)
-
-    if dest_dir[-1] != '/':
-      dest_dir += '/'
-
-    try:
-      data = self.runCmds([{ 'cmd': 'unzp %s %s' % (file_path, dest_dir)}])
-    except AgentError:
-      return None
-
-    return data
-
-  # external function
-  # returns:
-  #  success: status from test agent
-  #  failure: None
-  def reboot(self, ipAddr=None, port=30000):
-    cmd = 'rebt'
-
-    if (self.debug > 3): print "INFO: sending rebt command"
-
-    if (ipAddr is not None):
-    #create update.info file:
-      try:
-        destname = '/data/data/com.mozilla.SUTAgentAndroid/files/update.info'
-        data = "%s,%s\rrebooting\r" % (ipAddr, port)
-        self.runCmds([{ 'cmd': 'push %s %s' % (destname, len(data)),
-                        'data': data }])
-      except AgentError:
-        return None
-
-      ip, port = self.getCallbackIpAndPort(ipAddr, port)
-      cmd += " %s %s" % (ip, port)
-      # Set up our callback server
-      callbacksvr = callbackServer(ip, port, self.debug)
-
-    try:
-      status = self.runCmds([{ 'cmd': cmd }])
-    except AgentError:
-      return None
-
-    if (ipAddr is not None):
-      status = callbacksvr.disconnect()
-
-    if (self.debug > 3): print "INFO: rebt- got status back: " + str(status)
-    return status
-
-  # Returns information about the device:
-  # Directive indicates the information you want to get, your choices are:
-  # os - name of the os
-  # id - unique id of the device
-  # uptime - uptime of the device
-  # uptimemillis - uptime of the device in milliseconds (SUTAgent 1.11+)
-  # systime - system time of the device
-  # screen - screen resolution
-  # rotation - rotation of the device (in degrees)
-  # memory - memory stats
-  # process - list of running processes (same as ps)
-  # disk - total, free, available bytes on disk
-  # power - power status (charge, battery temp)
-  # all - all of them - or call it with no parameters to get all the information
-  # returns:
-  #   success: dict of info strings by directive name
-  #   failure: {}
-  def getInfo(self, directive=None):
-    data = None
-    result = {}
-    collapseSpaces = re.compile('  +')
-
-    directives = ['os','id','uptime','uptimemillis','systime','screen',
-                  'rotation','memory','process','disk','power']
-    if (directive in directives):
-      directives = [directive]
-
-    for d in directives:
-      try:
-        data = self.runCmds([{ 'cmd': 'info ' + d }])
-      except AgentError:
-        return result
-
-      if (data is None):
-        continue
-      data = collapseSpaces.sub(' ', data)
-      result[d] = data.split('\n')
-
-    # Get rid of any 0 length members of the arrays
-    for k, v in result.iteritems():
-      result[k] = filter(lambda x: x != '', result[k])
-
-    # Format the process output
-    if 'process' in result:
-      proclist = []
-      for l in result['process']:
-        if l:
-          proclist.append(l.split('\t'))
-      result['process'] = proclist
-
-    if (self.debug >= 3): print "results: " + str(result)
-    return result
-
-  """
-  Installs the application onto the device
-  Application bundle - path to the application bundle on the device
-  Destination - destination directory of where application should be
-                installed to (optional)
-  Returns None for success, or output if known failure
-  """
-  # external function
-  # returns:
-  #  success: output from agent for inst command
-  #  failure: None
-  def installApp(self, appBundlePath, destPath=None):
-    cmd = 'inst ' + appBundlePath
-    if destPath:
-      cmd += ' ' + destPath
-    try:
-      data = self.runCmds([{ 'cmd': cmd }])
-    except AgentError:
-      return None
-
-    f = re.compile('Failure')
-    for line in data.split():
-      if (f.match(line)):
-        return data
-    return None
-
-  """
-  Uninstalls the named application from device and causes a reboot.
-  Takes an optional argument of installation path - the path to where the application
-  was installed.
-  Returns True, but it doesn't mean anything other than the command was sent,
-  the reboot happens and we don't know if this succeeds or not.
-  """
-  # external function
-  # returns:
-  #  success: True
-  #  failure: None
-  def uninstallAppAndReboot(self, appName, installPath=None):
-    cmd = 'uninst ' + appName
-    if installPath:
-      cmd += ' ' + installPath
-    try:
-      data = self.runCmds([{ 'cmd': cmd }])
-    except AgentError:
-      return None
-
-    if (self.debug > 3): print "uninstallAppAndReboot: " + str(data)
-    return True
-
-  """
-  Updates the application on the device.
-  Application bundle - path to the application bundle on the device
-  Process name of application - used to end the process if the applicaiton is
-                                currently running
-  Destination - Destination directory to where the application should be
-                installed (optional)
-  ipAddr - IP address to await a callback ping to let us know that the device has updated
-           properly - defaults to current IP.
-  port - port to await a callback ping to let us know that the device has updated properly
-         defaults to 30000, and counts up from there if it finds a conflict
-  Returns True if succeeds, False if not
-  """
-  # external function
-  # returns:
-  #  success: text status from command or callback server
-  #  failure: None
-  def updateApp(self, appBundlePath, processName=None, destPath=None, ipAddr=None, port=30000):
-    status = None
-    cmd = 'updt '
-    if (processName == None):
-      # Then we pass '' for processName
-      cmd += "'' " + appBundlePath
-    else:
-      cmd += processName + ' ' + appBundlePath
-
-    if (destPath):
-      cmd += " " + destPath
-
-    if (ipAddr is not None):
-      ip, port = self.getCallbackIpAndPort(ipAddr, port)
-      cmd += " %s %s" % (ip, port)
-      # Set up our callback server
-      callbacksvr = callbackServer(ip, port, self.debug)
-
-    if (self.debug >= 3): print "INFO: updateApp using command: " + str(cmd)
-
-    try:
-      status = self.runCmds([{ 'cmd': cmd }])
-    except AgentError:
-      return None
-
-    if ipAddr is not None:
-      status = callbacksvr.disconnect()
-
-    if (self.debug >= 3): print "INFO: updateApp: got status back: " + str(status)
-
-    return status
-
-  """
-    return the current time on the device
-  """
-  # external function
-  # returns:
-  #  success: time in ms
-  #  failure: None
-  def getCurrentTime(self):
-    try:
-      data = self.runCmds([{ 'cmd': 'clok' }])
-    except AgentError:
-      return None
-
-    return data.strip()
-
-  """
-    Connect the ipaddress and port for a callback ping.  Defaults to current IP address
-    And ports starting at 30000.
-    NOTE: the detection for current IP address only works on Linux!
-  """
-  def getCallbackIpAndPort(self, aIp, aPort):
-    ip = aIp
-    nettools = NetworkTools()
-    if (ip == None):
-      ip = nettools.getLanIp()
-    if (aPort != None):
-      port = nettools.findOpenPort(ip, aPort)
-    else:
-      port = nettools.findOpenPort(ip, 30000)
-    return ip, port
-
-  """
-    Returns a properly formatted env string for the agent.
-    Input - env, which is either None, '', or a dict
-    Output - a quoted string of the form: '"envvar1=val1,envvar2=val2..."'
-    If env is None or '' return '' (empty quoted string)
-  """
-  def formatEnvString(self, env):
-    if (env == None or env == ''):
-      return ''
-
-    retVal = '"%s"' % ','.join(map(lambda x: '%s=%s' % (x[0], x[1]), env.iteritems()))
-    if (retVal == '""'):
-      return ''
-
-    return retVal
-
-  """
-    adjust the screen resolution on the device, REBOOT REQUIRED
-    NOTE: this only works on a tegra ATM
-    success: True
-    failure: False
-
-    supported resolutions: 640x480, 800x600, 1024x768, 1152x864, 1200x1024, 1440x900, 1680x1050, 1920x1080
-  """
-  def adjustResolution(self, width=1680, height=1050, type='hdmi'):
-    if self.getInfo('os')['os'][0].split()[0] != 'harmony-eng':
-      if (self.debug >= 2): print "WARNING: unable to adjust screen resolution on non Tegra device"
-      return False
-
-    results = self.getInfo('screen')
-    parts = results['screen'][0].split(':')
-    if (self.debug >= 3): print "INFO: we have a current resolution of %s, %s" % (parts[1].split()[0], parts[2].split()[0])
-
-    #verify screen type is valid, and set it to the proper value (https://bugzilla.mozilla.org/show_bug.cgi?id=632895#c4)
-    screentype = -1
-    if (type == 'hdmi'):
-      screentype = 5
-    elif (type == 'vga' or type == 'crt'):
-      screentype = 3
-    else:
-      return False
-
-    #verify we have numbers
-    if not (isinstance(width, int) and isinstance(height, int)):
-      return False
-
-    if (width < 100 or width > 9999):
-      return False
-
-    if (height < 100 or height > 9999):
-      return False
-
-    if (self.debug >= 3): print "INFO: adjusting screen resolution to %s, %s and rebooting" % (width, height)
-    try:
-      self.runCmds([{ 'cmd': "exec setprop persist.tegra.dpy%s.mode.width %s" % (screentype, width) }])
-      self.runCmds([{ 'cmd': "exec setprop persist.tegra.dpy%s.mode.height %s" % (screentype, height) }])
-    except AgentError:
-      return False
-
-    return True
-
-  # external function
-  # returns:
-  #  success: True
-  #  failure: False
-  def chmodDir(self, remoteDir):
-    try:
-      self.runCmds([{ 'cmd': "chmod "+remoteDir }])
-    except AgentError:
-      return False
-    return True
-
-gCallbackData = ''
-
-class myServer(SocketServer.TCPServer):
-  allow_reuse_address = True
-
-class callbackServer():
-  def __init__(self, ip, port, debuglevel):
-    global gCallbackData
-    if (debuglevel >= 1): print "DEBUG: gCallbackData is: %s on port: %s" % (gCallbackData, port)
-    gCallbackData = ''
-    self.ip = ip
-    self.port = port
-    self.connected = False
-    self.debug = debuglevel
-    if (self.debug >= 3): print "Creating server with " + str(ip) + ":" + str(port)
-    self.server = myServer((ip, port), self.myhandler)
-    self.server_thread = Thread(target=self.server.serve_forever)
-    self.server_thread.setDaemon(True)
-    self.server_thread.start()
-
-  def disconnect(self, step = 60, timeout = 600):
-    t = 0
-    if (self.debug >= 3): print "Calling disconnect on callback server"
-    while t < timeout:
-      if (gCallbackData):
-        # Got the data back
-        if (self.debug >= 3): print "Got data back from agent: " + str(gCallbackData)
-        break
-      else:
-        if (self.debug >= 0): print '.',
-      time.sleep(step)
-      t += step
-
-    try:
-      if (self.debug >= 3): print "Shutting down server now"
-      self.server.shutdown()
-    except:
-      if (self.debug >= 1): print "Unable to shutdown callback server - check for a connection on port: " + str(self.port)
-
-    #sleep 1 additional step to ensure not only we are online, but all our services are online
-    time.sleep(step)
-    return gCallbackData
-
-  class myhandler(SocketServer.BaseRequestHandler):
-    def handle(self):
-      global gCallbackData
-      gCallbackData = self.request.recv(1024)
-      #print "Callback Handler got data: " + str(gCallbackData)
-      self.request.send("OK")
-
deleted file mode 100644
--- a/build/mobile/droid.py
+++ /dev/null
@@ -1,83 +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/.
-
-from devicemanagerADB import DeviceManagerADB
-from devicemanagerSUT import DeviceManagerSUT
-import StringIO
-
-class DroidMixin(object):
-  """Mixin to extend DeviceManager with Android-specific functionality"""
-
-  def launchApplication(self, appName, activityName, intent, url=None,
-                        extras=None):
-    """
-    Launches an Android application
-    returns:
-    success: True
-    failure: False
-    """
-    # only one instance of an application may be running at once
-    if self.processExist(appName):
-      return False
-
-    acmd = [ "am", "start", "-W", "-n", "%s/%s" % (appName, activityName)]
-
-    if intent:
-      acmd.extend(["-a", intent])
-
-    if extras:
-      for (key, val) in extras.iteritems():
-        if type(val) is int:
-          extraTypeParam = "--ei"
-        elif type(val) is bool:
-          extraTypeParam = "--ez"
-        else:
-          extraTypeParam = "--es"
-        acmd.extend([extraTypeParam, str(key), str(val)])
-
-    if url:
-      acmd.extend(["-d", url])
-
-    # shell output not that interesting and debugging logs should already
-    # show what's going on here... so just create an empty memory buffer
-    # and ignore
-    shellOutput = StringIO.StringIO()
-    if self.shell(acmd, shellOutput) == 0:
-      return True
-
-    return False
-
-  def launchFennec(self, appName, intent="android.intent.action.VIEW",
-                   mozEnv=None, extraArgs=None, url=None):
-    """
-    Convenience method to launch Fennec on Android with various debugging
-    arguments
-    WARNING: FIXME: This would go better in mozrunner. Please do not
-    use this method if you are not comfortable with it going away sometime
-    in the near future
-    returns:
-    success: True
-    failure: False
-    """
-    extras = {}
-
-    if mozEnv:
-      # mozEnv is expected to be a dictionary of environment variables: Fennec
-      # itself will set them when launched
-      for (envCnt, (envkey, envval)) in enumerate(mozEnv.iteritems()):
-        extras["env" + str(envCnt)] = envkey + "=" + envval
-
-    # Additional command line arguments that fennec will read and use (e.g.
-    # with a custom profile)
-    if extraArgs:
-      extras['args'] = " ".join(extraArgs)
-
-    return self.launchApplication(appName, ".App", intent, url=url,
-                                  extras=extras)
-
-class DroidADB(DeviceManagerADB, DroidMixin):
-  pass
-
-class DroidSUT(DeviceManagerSUT, DroidMixin):
-  pass
deleted file mode 100644
--- a/build/mobile/emulator.py
+++ /dev/null
@@ -1,296 +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/.
-
-from abc import abstractmethod
-import datetime
-from mozprocess import ProcessHandlerMixin
-import multiprocessing
-import os
-import re
-import shutil
-import socket
-import subprocess
-from telnetlib import Telnet
-import tempfile
-import time
-
-from emulator_battery import EmulatorBattery
-
-
-class LogcatProc(ProcessHandlerMixin):
-    """Process handler for logcat which saves all output to a logfile.
-    """
-
-    def __init__(self, logfile, cmd, **kwargs):
-        self.logfile = logfile
-        kwargs.setdefault('processOutputLine', []).append(self.log_output)
-        ProcessHandlerMixin.__init__(self, cmd, **kwargs)
-
-    def log_output(self, line):
-        f = open(self.logfile, 'a')
-        f.write(line + "\n")
-        f.flush()
-
-
-class Emulator(object):
-
-    deviceRe = re.compile(r"^emulator-(\d+)(\s*)(.*)$")
-
-    def __init__(self, noWindow=False, logcat_dir=None, arch="x86",
-                 emulatorBinary=None, res='480x800', userdata=None,
-                 memory='512', partition_size='512'):
-        self.port = None
-        self._emulator_launched = False
-        self.proc = None
-        self.local_port = None
-        self.telnet = None
-        self._tmp_userdata = None
-        self._adb_started = False
-        self.logcat_dir = logcat_dir
-        self.logcat_proc = None
-        self.arch = arch
-        self.binary = emulatorBinary
-        self.memory = str(memory)
-        self.partition_size = str(partition_size)
-        self.res = res
-        self.battery = EmulatorBattery(self)
-        self.noWindow = noWindow
-        self.dataImg = userdata
-        self.copy_userdata = self.dataImg is None
-
-    def __del__(self):
-        if self.telnet:
-            self.telnet.write('exit\n')
-            self.telnet.read_all()
-
-    @property
-    def args(self):
-        qemuArgs = [self.binary,
-                    '-kernel', self.kernelImg,
-                    '-sysdir', self.sysDir,
-                    '-data', self.dataImg]
-        if self.noWindow:
-            qemuArgs.append('-no-window')
-        qemuArgs.extend(['-memory', self.memory,
-                         '-partition-size', self.partition_size,
-                         '-verbose',
-                         '-skin', self.res,
-                         '-gpu', 'on',
-                         '-qemu'] + self.tail_args)
-        return qemuArgs
-
-    @property
-    def is_running(self):
-        if self._emulator_launched:
-            return self.proc is not None and self.proc.poll() is None
-        else:
-            return self.port is not None
-
-    def _default_adb(self):
-        adb = subprocess.Popen(['which', 'adb'],
-                               stdout=subprocess.PIPE,
-                               stderr=subprocess.STDOUT)
-        retcode = adb.wait()
-        if retcode == 0:
-            self.adb = adb.stdout.read().strip() # remove trailing newline
-        return retcode
-
-    def _check_for_adb(self):
-        if not os.path.exists(self.adb):
-            if self._default_adb() != 0:
-                raise Exception('adb not found!')
-
-    def _run_adb(self, args):
-        args.insert(0, self.adb)
-        adb = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
-        retcode = adb.wait()
-        if retcode:
-            raise Exception('adb terminated with exit code %d: %s'
-            % (retcode, adb.stdout.read()))
-        return adb.stdout.read()
-
-    def _get_telnet_response(self, command=None):
-        output = []
-        assert(self.telnet)
-        if command is not None:
-            self.telnet.write('%s\n' % command)
-        while True:
-            line = self.telnet.read_until('\n')
-            output.append(line.rstrip())
-            if line.startswith('OK'):
-                return output
-            elif line.startswith('KO:'):
-                raise Exception('bad telnet response: %s' % line)
-
-    def _run_telnet(self, command):
-        if not self.telnet:
-            self.telnet = Telnet('localhost', self.port)
-            self._get_telnet_response()
-        return self._get_telnet_response(command)
-
-    def close(self):
-        if self.is_running and self._emulator_launched:
-            self.proc.terminate()
-            self.proc.wait()
-        if self._adb_started:
-            self._run_adb(['kill-server'])
-            self._adb_started = False
-        if self.proc:
-            retcode = self.proc.poll()
-            self.proc = None
-            if self._tmp_userdata:
-                os.remove(self._tmp_userdata)
-                self._tmp_userdata = None
-            return retcode
-        if self.logcat_proc:
-            self.logcat_proc.kill()
-        return 0
-
-    def _get_adb_devices(self):
-        offline = set()
-        online = set()
-        output = self._run_adb(['devices'])
-        for line in output.split('\n'):
-            m = self.deviceRe.match(line)
-            if m:
-                if m.group(3) == 'offline':
-                    offline.add(m.group(1))
-                else:
-                    online.add(m.group(1))
-        return (online, offline)
-
-    def restart(self):
-        if not self._emulator_launched:
-            return
-        self.close()
-        self.start()
-
-    def start_adb(self):
-        result = self._run_adb(['start-server'])
-        # We keep track of whether we've started adb or not, so we know
-        # if we need to kill it.
-        if 'daemon started successfully' in result:
-            self._adb_started = True
-        else:
-            self._adb_started = False
-
-    def connect(self):
-        self._check_for_adb()
-        self.start_adb()
-
-        online, offline = self._get_adb_devices()
-        now = datetime.datetime.now()
-        while online == set([]):
-            time.sleep(1)
-            if datetime.datetime.now() - now > datetime.timedelta(seconds=60):
-                raise Exception('timed out waiting for emulator to be available')
-            online, offline = self._get_adb_devices()
-        self.port = int(list(online)[0])
-
-    @abstractmethod
-    def _locate_files(self):
-        pass
-
-    def start(self):
-        self._locate_files()
-        self.start_adb()
-
-        qemu_args = self.args[:]
-        if self.copy_userdata:
-            # Make a copy of the userdata.img for this instance of the emulator
-            # to use.
-            self._tmp_userdata = tempfile.mktemp(prefix='emulator')
-            shutil.copyfile(self.dataImg, self._tmp_userdata)
-            qemu_args[qemu_args.index('-data') + 1] = self._tmp_userdata
-
-        original_online, original_offline = self._get_adb_devices()
-
-        self.proc = subprocess.Popen(qemu_args,
-                                     stdout=subprocess.PIPE,
-                                     stderr=subprocess.PIPE)
-
-        online, offline = self._get_adb_devices()
-        now = datetime.datetime.now()
-        while online - original_online == set([]):
-            time.sleep(1)
-            if datetime.datetime.now() - now > datetime.timedelta(seconds=60):
-                raise Exception('timed out waiting for emulator to start')
-            online, offline = self._get_adb_devices()
-        self.port = int(list(online - original_online)[0])
-        self._emulator_launched = True
-
-        if self.logcat_dir:
-            self.save_logcat()
-
-        # setup DNS fix for networking
-        self._run_adb(['-s', 'emulator-%d' % self.port,
-                       'shell', 'setprop', 'net.dns1', '10.0.2.3'])
-
-    def _save_logcat_proc(self, filename, cmd):
-        self.logcat_proc = LogcatProc(filename, cmd)
-        self.logcat_proc.run()
-        self.logcat_proc.waitForFinish()
-        self.logcat_proc = None
-
-    def rotate_log(self, srclog, index=1):
-        """ Rotate a logfile, by recursively rotating logs further in the sequence,
-            deleting the last file if necessary.
-        """
-        destlog = os.path.join(self.logcat_dir, 'emulator-%d.%d.log' % (self.port, index))
-        if os.path.exists(destlog):
-            if index == 3:
-                os.remove(destlog)
-            else:
-                self.rotate_log(destlog, index + 1)
-        shutil.move(srclog, destlog)
-
-    def save_logcat(self):
-        """ Save the output of logcat to a file.
-        """
-        filename = os.path.join(self.logcat_dir, "emulator-%d.log" % self.port)
-        if os.path.exists(filename):
-            self.rotate_log(filename)
-        cmd = [self.adb, '-s', 'emulator-%d' % self.port, 'logcat']
-
-        # We do this in a separate process because we call mozprocess's
-        # waitForFinish method to process logcat's output, and this method
-        # blocks.
-        proc = multiprocessing.Process(target=self._save_logcat_proc, args=(filename, cmd))
-        proc.daemon = True
-        proc.start()
-
-    def setup_port_forwarding(self, remote_port):
-        """ Set up TCP port forwarding to the specified port on the device,
-            using any availble local port, and return the local port.
-        """
-
-        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
-        s.bind(("", 0))
-        local_port = s.getsockname()[1]
-        s.close()
-
-        self._run_adb(['-s', 'emulator-%d' % self.port, 'forward',
-                       'tcp:%d' % local_port,
-                       'tcp:%d' % remote_port])
-
-        self.local_port = local_port
-
-        return local_port
-
-    def wait_for_port(self, timeout=300):
-        assert(self.local_port)
-        starttime = datetime.datetime.now()
-        while datetime.datetime.now() - starttime < datetime.timedelta(seconds=timeout):
-            try:
-                sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
-                sock.connect(('localhost', self.local_port))
-                data = sock.recv(16)
-                sock.close()
-                if '"from"' in data:
-                    return True
-            except:
-                import traceback
-                print traceback.format_exc()
-            time.sleep(1)
-        return False
deleted file mode 100644
--- a/build/mobile/emulator_battery.py
+++ /dev/null
@@ -1,52 +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/.
-
-class EmulatorBattery(object):
-
-    def __init__(self, emulator):
-        self.emulator = emulator
-
-    def get_state(self):
-        status = {}
-        state = {}
-
-        response = self.emulator._run_telnet('power display')
-        for line in response:
-            if ':' in line:
-                field, value = line.split(':')
-                value = value.strip()
-                if value == 'true':
-                    value = True
-                elif value == 'false':
-                    value = False
-                elif field == 'capacity':
-                    value = float(value)
-                status[field] = value
-
-        state['level'] = status.get('capacity', 0.0) / 100
-        if status.get('AC') == 'online':
-            state['charging'] = True
-        else:
-            state['charging'] = False
-
-        return state
-
-    def get_charging(self):
-        return self.get_state()['charging']
-
-    def get_level(self):
-        return self.get_state()['level']
-
-    def set_level(self, level):
-        self.emulator._run_telnet('power capacity %d' % (level * 100))
-
-    def set_charging(self, charging):
-        if charging:
-            cmd = 'power ac on'
-        else:
-            cmd = 'power ac off'
-        self.emulator._run_telnet(cmd)
-
-    charging = property(get_charging, set_charging)
-    level = property(get_level, set_level)
--- a/build/pymake/pymake/process.py
+++ b/build/pymake/pymake/process.py
@@ -259,18 +259,18 @@ class PythonJob(Job):
             print >>sys.stderr, e
             return e.exitcode
         except:
             e = sys.exc_info()[1]
             if isinstance(e, SystemExit) and (e.code == 0 or e.code is None):
                 pass # sys.exit(0) is not a failure
             else:
                 print >>sys.stderr, e
-                print >>sys.stderr, traceback.print_exc()
-                return (e.code if isinstance(e.code, int) else 1)
+                traceback.print_exc()
+                return -127
         finally:
             os.environ.clear()
             os.environ.update(oldenv)
         return 0
 
 def job_runner(job):
     """
     Run a job. Called in a Process pool.
new file mode 100644
--- /dev/null
+++ b/build/pymake/tests/native-command-raise.mk
@@ -0,0 +1,9 @@
+#T gmake skip
+#T returncode: 2
+#T grep-for: "Exception: info-exception"
+
+CMD = %pycmd asplode_raise
+PYCOMMANDPATH = $(TESTPATH) $(TESTPATH)/subdir
+
+all:
+	@$(CMD) info-exception
--- a/build/pymake/tests/pycmd.py
+++ b/build/pymake/tests/pycmd.py
@@ -25,8 +25,11 @@ def convertasplode(arg):
 
 def asplode(args):
   arg0 = convertasplode(args[0])
   sys.exit(arg0)
 
 def asplode_return(args):
   arg0 = convertasplode(args[0])
   return arg0
+
+def asplode_raise(args):
+  raise Exception(args[0])
--- a/content/base/src/nsPropertyTable.h
+++ b/content/base/src/nsPropertyTable.h
@@ -19,16 +19,17 @@
  * themselves.  Nodes can be any type of object; the hashtable keys are
  * nsIAtom pointers, and the values are void pointers.
  */
 
 #ifndef nsPropertyTable_h_
 #define nsPropertyTable_h_
 
 #include "nscore.h"
+#include "prtypes.h"
 
 class nsIAtom;
 typedef PRUptrdiff PtrBits;
 
 typedef void
 (*NSPropertyFunc)(void           *aObject,
                   nsIAtom        *aPropertyName,
                   void           *aPropertyValue,
--- a/content/canvas/src/WebGLContext.cpp
+++ b/content/canvas/src/WebGLContext.cpp
@@ -380,18 +380,16 @@ WebGLContext::SetDimensions(int32_t widt
     // in the WebGLContext constructor as we don't have a canvas element yet there.
     // Here is the right place to do so, as we are about to create the OpenGL context
     // and that is what can fail if we already have too many.
     LoseOldestWebGLContextIfLimitExceeded();
 
     // Get some prefs for some preferred/overriden things
     NS_ENSURE_TRUE(Preferences::GetRootBranch(), NS_ERROR_FAILURE);
 
-    bool forceOSMesa =
-        Preferences::GetBool("webgl.force_osmesa", false);
 #ifdef XP_WIN
     bool preferEGL =
         Preferences::GetBool("webgl.prefer-egl", false);
     bool preferOpenGL =
         Preferences::GetBool("webgl.prefer-native-gl", false);
 #endif
     bool forceEnabled =
         Preferences::GetBool("webgl.force-enabled", false);
@@ -502,26 +500,16 @@ WebGLContext::SetDimensions(int32_t widt
     // allow forcing GL and not EGL/ANGLE
     if (useMesaLlvmPipe || PR_GetEnv("MOZ_WEBGL_FORCE_OPENGL")) {
         preferEGL = false;
         useANGLE = false;
         useOpenGL = true;
     }
 #endif
 
-    // if we're forcing osmesa, do it first
-    if (forceOSMesa) {
-        gl = gl::GLContextProviderOSMesa::CreateOffscreen(gfxIntSize(width, height), format);
-        if (!gl || !InitAndValidateGL()) {
-            GenerateWarning("OSMesa forced, but creating context failed -- aborting!");
-            return NS_ERROR_FAILURE;
-        }
-        GenerateWarning("Using software rendering via OSMesa (THIS WILL BE SLOW)");
-    }
-
 #ifdef XP_WIN
     // if we want EGL, try it now
     if (!gl && (preferEGL || useANGLE) && !preferOpenGL) {
         gl = gl::GLContextProviderEGL::CreateOffscreen(gfxIntSize(width, height), format);
         if (!gl || !InitAndValidateGL()) {
             GenerateWarning("Error during ANGLE OpenGL ES initialization");
             return NS_ERROR_FAILURE;
         }
@@ -537,29 +525,16 @@ WebGLContext::SetDimensions(int32_t widt
                                                                format, flag);
         if (gl && !InitAndValidateGL()) {
             GenerateWarning("Error during %s initialization", 
                             useMesaLlvmPipe ? "Mesa LLVMpipe" : "OpenGL");
             return NS_ERROR_FAILURE;
         }
     }
 
-    // finally, try OSMesa
-    if (!gl) {
-        gl = gl::GLContextProviderOSMesa::CreateOffscreen(gfxIntSize(width, height), format);
-        if (gl) {
-            if (!InitAndValidateGL()) {
-                GenerateWarning("Error during OSMesa initialization");
-                return NS_ERROR_FAILURE;
-            } else {
-                GenerateWarning("Using software rendering via OSMesa (THIS WILL BE SLOW)");
-            }
-        }
-    }
-
     if (!gl) {
         GenerateWarning("Can't get a usable WebGL context");
         return NS_ERROR_FAILURE;
     }
 
 #ifdef DEBUG
     if (gl->DebugMode()) {
         printf_stderr("--- WebGL context created: %p\n", gl.get());
--- a/content/xul/templates/src/nsContentSupportMap.h
+++ b/content/xul/templates/src/nsContentSupportMap.h
@@ -1,16 +1,17 @@
 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /* 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/. */
 
 #ifndef nsContentSupportMap_h__
 #define nsContentSupportMap_h__
 
+#include "prtypes.h"
 #include "pldhash.h"
 #include "nsFixedSizeAllocator.h"
 #include "nsTemplateMatch.h"
 
 /**
  * The nsContentSupportMap maintains a mapping from a "resource element"
  * in the content tree to the nsTemplateMatch that was used to instantiate it. This
  * is necessary to allow the XUL content to be built lazily. Specifically,
--- a/dom/base/nsDOMWindowUtils.cpp
+++ b/dom/base/nsDOMWindowUtils.cpp
@@ -1434,27 +1434,19 @@ nsDOMWindowUtils::FindElementWithViewId(
 
   nsRefPtr<nsIContent> content = nsLayoutUtils::FindContentFor(aID);
   return content ? CallQueryInterface(content, aResult) : NS_OK;
 }
 
 NS_IMETHODIMP
 nsDOMWindowUtils::GetScreenPixelsPerCSSPixel(float* aScreenPixels)
 {
-  *aScreenPixels = 1;
-
-  if (!nsContentUtils::IsCallerTrustedForRead())
-    return NS_ERROR_DOM_SECURITY_ERR;
-  nsPresContext* presContext = GetPresContext();
-  if (!presContext)
-    return NS_OK;
-
-  *aScreenPixels = float(nsPresContext::AppUnitsPerCSSPixel())/
-      presContext->AppUnitsPerDevPixel();
-  return NS_OK;
+  nsCOMPtr<nsPIDOMWindow> window = do_QueryReferent(mWindow);
+  NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
+  return window->GetDevicePixelRatio(aScreenPixels);
 }
 
 NS_IMETHODIMP
 nsDOMWindowUtils::DispatchDOMEventViaPresShell(nsIDOMNode* aTarget,
                                                nsIDOMEvent* aEvent,
                                                bool aTrusted,
                                                bool* aRetVal)
 {
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -3862,16 +3862,36 @@ nsGlobalWindow::GetMozInnerScreenY(float
   FORWARD_TO_OUTER(GetMozInnerScreenY, (aScreenY), NS_ERROR_NOT_INITIALIZED);
 
   nsRect r = GetInnerScreenRect();
   *aScreenY = nsPresContext::AppUnitsToFloatCSSPixels(r.y);
   return NS_OK;
 }
 
 NS_IMETHODIMP
+nsGlobalWindow::GetDevicePixelRatio(float* aRatio)
+{
+  FORWARD_TO_OUTER(GetDevicePixelRatio, (aRatio), NS_ERROR_NOT_INITIALIZED);
+
+  *aRatio = 1.0;
+
+  if (!mDocShell)
+    return NS_OK;
+
+  nsCOMPtr<nsPresContext> presContext;
+  mDocShell->GetPresContext(getter_AddRefs(presContext));
+  if (!presContext)
+    return NS_OK;
+
+  *aRatio = float(nsPresContext::AppUnitsPerCSSPixel())/
+      presContext->AppUnitsPerDevPixel();
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 nsGlobalWindow::GetMozPaintCount(uint64_t* aResult)
 {
   FORWARD_TO_OUTER(GetMozPaintCount, (aResult), NS_ERROR_NOT_INITIALIZED);
 
   *aResult = 0;
 
   if (!mDocShell)
     return NS_OK;
--- a/dom/bindings/DOMJSProxyHandler.cpp
+++ b/dom/bindings/DOMJSProxyHandler.cpp
@@ -13,17 +13,16 @@
 #include "XPCWrapper.h"
 #include "WrapperFactory.h"
 #include "nsDOMClassInfo.h"
 #include "nsGlobalWindow.h"
 #include "nsWrapperCacheInlines.h"
 #include "mozilla/dom/BindingUtils.h"
 
 #include "jsapi.h"
-#include "jsatom.h"
 
 using namespace JS;
 
 namespace mozilla {
 namespace dom {
 
 jsid s_length_id = JSID_VOID;
 
--- a/dom/bindings/DOMJSProxyHandler.h
+++ b/dom/bindings/DOMJSProxyHandler.h
@@ -2,17 +2,17 @@
 /* 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/. */
 
 #ifndef mozilla_dom_DOMJSProxyHandler_h
 #define mozilla_dom_DOMJSProxyHandler_h
 
 #include "jsapi.h"
-#include "jsatom.h"
+#include "jsfriendapi.h"
 #include "jsproxy.h"
 #include "xpcpublic.h"
 #include "nsString.h"
 #include "mozilla/Likely.h"
 
 #define DOM_PROXY_OBJECT_SLOT js::JSSLOT_PROXY_PRIVATE
 
 namespace mozilla {
--- a/dom/camera/CameraControlImpl.cpp
+++ b/dom/camera/CameraControlImpl.cpp
@@ -218,22 +218,24 @@ CameraControlImpl::StartPreview(DOMCamer
 
 void
 CameraControlImpl::StopPreview()
 {
   nsCOMPtr<nsIRunnable> stopPreviewTask = new StopPreviewTask(this);
   mCameraThread->Dispatch(stopPreviewTask, NS_DISPATCH_NORMAL);
 }
 
-void
+bool
 CameraControlImpl::ReceiveFrame(void* aBuffer, ImageFormat aFormat, FrameBuilder aBuilder)
 {
-  if (mDOMPreview) {
-    mDOMPreview->ReceiveFrame(aBuffer, aFormat, aBuilder);
+  if (!mDOMPreview) {
+    return false;
   }
+
+  return mDOMPreview->ReceiveFrame(aBuffer, aFormat, aBuilder);
 }
 
 NS_IMETHODIMP
 GetPreviewStreamResult::Run()
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   if (mOnSuccessCb) {
--- a/dom/camera/CameraControlImpl.h
+++ b/dom/camera/CameraControlImpl.h
@@ -89,17 +89,17 @@ public:
   virtual double GetParameterDouble(uint32_t aKey) = 0;
   virtual void GetParameter(uint32_t aKey, nsTArray<CameraRegion>& aRegions) = 0;
   virtual void SetParameter(const char* aKey, const char* aValue) = 0;
   virtual void SetParameter(uint32_t aKey, const char* aValue) = 0;
   virtual void SetParameter(uint32_t aKey, double aValue) = 0;
   virtual void SetParameter(uint32_t aKey, const nsTArray<CameraRegion>& aRegions) = 0;
   virtual nsresult PushParameters() = 0;
 
-  void ReceiveFrame(void* aBuffer, ImageFormat aFormat, FrameBuilder aBuilder);
+  bool ReceiveFrame(void* aBuffer, ImageFormat aFormat, FrameBuilder aBuilder);
 
 protected:
   virtual ~CameraControlImpl()
   {
     DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
   }
 
   virtual nsresult GetPreviewStreamImpl(GetPreviewStreamTask* aGetPreviewStream) = 0;
--- a/dom/camera/DOMCameraPreview.cpp
+++ b/dom/camera/DOMCameraPreview.cpp
@@ -165,34 +165,35 @@ DOMCameraPreview::~DOMCameraPreview()
 }
 
 bool
 DOMCameraPreview::HaveEnoughBuffered()
 {
   return mInput->HaveEnoughBuffered(TRACK_VIDEO);
 }
 
-void
+bool
 DOMCameraPreview::ReceiveFrame(void* aBuffer, ImageFormat aFormat, FrameBuilder aBuilder)
 {
   DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
   if (!aBuffer || !aBuilder) {
-    return;
+    return false;
   }
   if (mState != STARTED) {
-    return;
+    return false;
   }
 
   ImageFormat format = aFormat;
   nsRefPtr<Image> image = mImageContainer->CreateImage(&format, 1);
   aBuilder(image, aBuffer, mWidth, mHeight);
 
   // AppendFrame() takes over image's reference
   mVideoSegment.AppendFrame(image.forget(), 1, gfxIntSize(mWidth, mHeight));
   mInput->AppendToTrack(TRACK_VIDEO, &mVideoSegment);
+  return true;
 }
 
 void
 DOMCameraPreview::Start()
 {
   NS_ASSERTION(NS_IsMainThread(), "Start() not called from main thread");
   if (mState != STOPPED) {
     return;
--- a/dom/camera/DOMCameraPreview.h
+++ b/dom/camera/DOMCameraPreview.h
@@ -25,17 +25,17 @@ typedef void (*FrameBuilder)(Image* aIma
  */
 class DOMCameraPreview : public nsDOMMediaStream
 {
 protected:
   enum { TRACK_VIDEO = 1 };
 
 public:
   DOMCameraPreview(ICameraControl* aCameraControl, uint32_t aWidth, uint32_t aHeight, uint32_t aFramesPerSecond = 30);
-  void ReceiveFrame(void* aBuffer, ImageFormat aFormat, FrameBuilder aBuilder);
+  bool ReceiveFrame(void* aBuffer, ImageFormat aFormat, FrameBuilder aBuilder);
   bool HaveEnoughBuffered();
 
   NS_IMETHODIMP
   GetCurrentTime(double* aCurrentTime) {
     return nsDOMMediaStream::GetCurrentTime(aCurrentTime);
   }
 
   void Start();   // called by the MediaStreamListener to start preview
--- a/dom/camera/GonkCameraControl.cpp
+++ b/dom/camera/GonkCameraControl.cpp
@@ -836,12 +836,14 @@ GonkFrameBuilder(Image* aImage, void* aB
   data.mGraphicBuffer = static_cast<layers::GraphicBufferLocked*>(aBuffer);
   data.mPicSize = gfxIntSize(aWidth, aHeight);
   videoImage->SetData(data);
 }
 
 void
 ReceiveFrame(nsGonkCameraControl* gc, layers::GraphicBufferLocked* aBuffer)
 {
-  gc->ReceiveFrame(aBuffer, ImageFormat::GONK_IO_SURFACE, GonkFrameBuilder);
+  if (!gc->ReceiveFrame(aBuffer, ImageFormat::GONK_IO_SURFACE, GonkFrameBuilder)) {
+    aBuffer->Unlock();
+  }
 }
 
 } // namespace mozilla
--- a/dom/camera/GonkNativeWindow.cpp
+++ b/dom/camera/GonkNativeWindow.cpp
@@ -19,25 +19,24 @@
 
 #include "base/basictypes.h"
 #include "GonkCameraHwMgr.h"
 #include "mozilla/layers/ShadowLayerUtilsGralloc.h"
 #include "mozilla/layers/ImageBridgeChild.h"
 #include "GonkNativeWindow.h"
 #include "nsDebug.h"
 
-// enable debug logging by setting to 1
-#define CNW_DEBUG 0
-#if CNW_DEBUG
-#define CNW_LOGD(...) {(void)printf_stderr(__VA_ARGS__);}
-#else
-#define CNW_LOGD(...) ((void)0)
-#endif
-
-#define CNW_LOGE(...) {(void)printf_stderr(__VA_ARGS__);}
+/**
+ * DOM_CAMERA_LOGI() is enabled in debug builds, and turned on by setting
+ * NSPR_LOG_MODULES=Camera:N environment variable, where N >= 3.
+ *
+ * CNW_LOGE() is always enabled.
+ */
+#define CNW_LOGD(...)   DOM_CAMERA_LOGI(__VA_ARGS__)
+#define CNW_LOGE(...)   {(void)printf_stderr(__VA_ARGS__);}
 
 using namespace android;
 using namespace mozilla::layers;
 
 GonkNativeWindow::GonkNativeWindow(GonkNativeWindowNewFrameCallback* aCallback)
   : mNewFrameCallback(aCallback)
 {
     GonkNativeWindow::init();
--- a/dom/camera/GonkNativeWindow.h
+++ b/dom/camera/GonkNativeWindow.h
@@ -31,29 +31,31 @@
 #include <ui/GraphicBuffer.h>
 #include <ui/Rect.h>
 #include <utils/String8.h>
 #include <utils/threads.h>
 
 #include "mozilla/layers/LayersSurfaces.h"
 #include "mozilla/layers/ImageBridgeChild.h"
 #include "GonkIOSurfaceImage.h"
+#include "CameraCommon.h"
 
 namespace android {
 
 // The user of GonkNativeWindow who wants to receive notification of
 // new frames should implement this interface.
 class GonkNativeWindowNewFrameCallback {
 public:
     virtual void OnNewFrame() = 0;
 };
 
 class GonkNativeWindow : public EGLNativeBase<ANativeWindow, GonkNativeWindow, RefBase>
 {
     typedef mozilla::layers::SurfaceDescriptor SurfaceDescriptor;
+
 public:
     enum { MIN_UNDEQUEUED_BUFFERS = 2 };
     enum { MIN_BUFFER_SLOTS = MIN_UNDEQUEUED_BUFFERS };
     enum { NUM_BUFFER_SLOTS = 32 };
 
     GonkNativeWindow();
     GonkNativeWindow(GonkNativeWindowNewFrameCallback* aCallback);
     ~GonkNativeWindow(); // this class cannot be overloaded
@@ -224,45 +226,52 @@ private:
     // mGeneration is the current generation of buffer slots
     uint32_t mGeneration;
 
     GonkNativeWindowNewFrameCallback* mNewFrameCallback;
 };
 
 
 // CameraGraphicBuffer maintains the buffer returned from GonkNativeWindow
-class CameraGraphicBuffer : public mozilla::layers::GraphicBufferLocked {
+class CameraGraphicBuffer : public mozilla::layers::GraphicBufferLocked
+{
     typedef mozilla::layers::SurfaceDescriptor SurfaceDescriptor;
+
 public:
     CameraGraphicBuffer(GonkNativeWindow* aNativeWindow,
                         uint32_t aIndex,
                         uint32_t aGeneration,
                         SurfaceDescriptor aBuffer)
         : GraphicBufferLocked(aBuffer)
-          , mNativeWindow(aNativeWindow)
-          , mIndex(aIndex)
-          , mGeneration(aGeneration)
-          , mLocked(true)
-    {}
+        , mNativeWindow(aNativeWindow)
+        , mIndex(aIndex)
+        , mGeneration(aGeneration)
+        , mLocked(true)
+    {
+        DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
+    }
 
-    virtual ~CameraGraphicBuffer() {}
+    virtual ~CameraGraphicBuffer()
+    {
+        DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
+    }
 
     // Unlock either returns the buffer to the native window or
     // destroys the buffer if the window is already released.
-    virtual void Unlock()  MOZ_OVERRIDE
+    virtual void Unlock() MOZ_OVERRIDE
     {
         if (mLocked) {
-            // The window might has been destroyed. The buffer is no longer
+            // The window might have been destroyed. The buffer is no longer
             // valid at that point.
             sp<GonkNativeWindow> window = mNativeWindow.promote();
             if (window.get() && window->returnBuffer(mIndex, mGeneration)) {
                 mLocked = false;
             } else {
                 // If the window doesn't exist any more, release the buffer
-                // by ourself.
+                // directly.
                 ImageBridgeChild *ibc = ImageBridgeChild::GetSingleton();
                 ibc->DeallocSurfaceDescriptorGralloc(mSurfaceDescriptor);
             }
         }
     }
 
 protected:
     wp<GonkNativeWindow> mNativeWindow;
--- a/dom/devicestorage/nsDeviceStorage.cpp
+++ b/dom/devicestorage/nsDeviceStorage.cpp
@@ -513,43 +513,43 @@ nsDOMDeviceStorage::SetRootDirectoryForT
   if (aType.Equals(NS_LITERAL_STRING("pictures"))) {
 #ifdef MOZ_WIDGET_GONK
     NS_NewLocalFile(NS_LITERAL_STRING("/sdcard"), false, getter_AddRefs(f));
 #elif defined (MOZ_WIDGET_COCOA)
     dirService->Get(NS_OSX_PICTURE_DOCUMENTS_DIR, NS_GET_IID(nsIFile), getter_AddRefs(f));
 #elif defined (XP_UNIX)
     dirService->Get(NS_UNIX_XDG_PICTURES_DIR, NS_GET_IID(nsIFile), getter_AddRefs(f));
 #elif defined (XP_WIN)
-    dirService->Get(NS_WIN_PERSONAL_DIR, NS_GET_IID(nsIFile), getter_AddRefs(f));
+    dirService->Get(NS_WIN_PICTURES_DIR, NS_GET_IID(nsIFile), getter_AddRefs(f));
 #endif
   }
 
   // Video directory
   else if (aType.Equals(NS_LITERAL_STRING("videos"))) {
 #ifdef MOZ_WIDGET_GONK
     NS_NewLocalFile(NS_LITERAL_STRING("/sdcard"), false, getter_AddRefs(f));
 #elif defined (MOZ_WIDGET_COCOA)
     dirService->Get(NS_OSX_MOVIE_DOCUMENTS_DIR, NS_GET_IID(nsIFile), getter_AddRefs(f));
 #elif defined (XP_UNIX)
     dirService->Get(NS_UNIX_XDG_VIDEOS_DIR, NS_GET_IID(nsIFile), getter_AddRefs(f));
 #elif defined (XP_WIN)
-    dirService->Get(NS_WIN_PERSONAL_DIR, NS_GET_IID(nsIFile), getter_AddRefs(f));
+    dirService->Get(NS_WIN_VIDEOS_DIR, NS_GET_IID(nsIFile), getter_AddRefs(f));
 #endif
   }
 
   // Music directory
   else if (aType.Equals(NS_LITERAL_STRING("music"))) {
 #ifdef MOZ_WIDGET_GONK
     NS_NewLocalFile(NS_LITERAL_STRING("/sdcard"), false, getter_AddRefs(f));
 #elif defined (MOZ_WIDGET_COCOA)
     dirService->Get(NS_OSX_MUSIC_DOCUMENTS_DIR, NS_GET_IID(nsIFile), getter_AddRefs(f));
 #elif defined (XP_UNIX)
     dirService->Get(NS_UNIX_XDG_MUSIC_DIR, NS_GET_IID(nsIFile), getter_AddRefs(f));
 #elif defined (XP_WIN)
-    dirService->Get(NS_WIN_PERSONAL_DIR, NS_GET_IID(nsIFile), getter_AddRefs(f));
+    dirService->Get(NS_WIN_MUSIC_DIR, NS_GET_IID(nsIFile), getter_AddRefs(f));
 #endif
   }
 
   // in testing, we default all device storage types to a temp directory
   if (f && mozilla::Preferences::GetBool("device.storage.testing", false)) {
     dirService->Get(NS_OS_TEMP_DIR, NS_GET_IID(nsIFile), getter_AddRefs(f));
     if (f) {
       f->AppendRelativeNativePath(NS_LITERAL_CSTRING("device-storage-testing"));
--- a/dom/interfaces/base/nsIDOMWindow.idl
+++ b/dom/interfaces/base/nsIDOMWindow.idl
@@ -27,17 +27,17 @@ interface nsIDOMMozURLProperty : nsISupp
  * The nsIDOMWindow interface is the primary interface for a DOM
  * window object. It represents a single window object that may
  * contain child windows if the document in the window contains a
  * HTML frameset document or if the document contains iframe elements.
  *
  * @see <http://www.whatwg.org/html/#window>
  */
 
-[scriptable, uuid(A1AF6CD9-C6E7-4037-99F8-DBCA1B03E345)]
+[scriptable, uuid(afeb6529-06f1-47e8-98c6-c7bfadb4c1ff)]
 interface nsIDOMWindow : nsISupports
 {
   // the current browsing context
   readonly attribute nsIDOMWindow                       window;
 
   /* [replaceable] self */
   readonly attribute nsIDOMWindow                       self;
 
@@ -370,16 +370,17 @@ interface nsIDOMWindow : nsISupports
   // XXX Shouldn't this be in nsIDOMChromeWindow?
   /* [replaceable] controllers */
   readonly attribute nsIControllers                     controllers;
 
            attribute DOMString                          defaultStatus;
 
   readonly attribute float                              mozInnerScreenX;
   readonly attribute float                              mozInnerScreenY;
+  readonly attribute float                              devicePixelRatio;
 
   /* The maximum offset that the window can be scrolled to
      (i.e., the document width/height minus the scrollport width/height) */
   readonly attribute long                               scrollMaxX;
   readonly attribute long                               scrollMaxY;
 
            attribute boolean                            fullScreen;
 
--- a/dom/workers/File.cpp
+++ b/dom/workers/File.cpp
@@ -6,17 +6,16 @@
 
 #include "File.h"
 
 #include "nsIDOMFile.h"
 #include "nsDOMBlobBuilder.h"
 #include "nsError.h"
 
 #include "jsapi.h"
-#include "jsatom.h"
 #include "jsfriendapi.h"
 #include "nsCOMPtr.h"
 #include "nsJSUtils.h"
 #include "nsStringGlue.h"
 
 #include "Exceptions.h"
 #include "WorkerInlines.h"
 #include "WorkerPrivate.h"
--- a/dom/workers/FileReaderSync.cpp
+++ b/dom/workers/FileReaderSync.cpp
@@ -5,17 +5,16 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "FileReaderSync.h"
 
 #include "nsIDOMFile.h"
 #include "nsError.h"
 
 #include "jsapi.h"
-#include "jsatom.h"
 #include "jsfriendapi.h"
 #include "nsJSUtils.h"
 
 #include "Exceptions.h"
 #include "File.h"
 #include "FileReaderSyncPrivate.h"
 #include "WorkerInlines.h"
 
--- a/editor/libeditor/base/tests/test_dragdrop.html
+++ b/editor/libeditor/base/tests/test_dragdrop.html
@@ -12,16 +12,17 @@
 </head>
 
 <body>
   <span id="text" style="font-size: 40px;">Some Text</span>
 
   <input id="input" value="Drag Me">
   <textarea id="textarea">Some Text To Drag</textarea>
   <p id="contenteditable" contenteditable="true">This is some <b id="bold">editable</b> text.</p>
+  <p id="nestedce" contenteditable="true"><span id="first"> </span>First letter <span id="noneditable" contenteditable="false">Middle</span> Last part</p>
 
 <script type="application/javascript">
 
 SimpleTest.waitForExplicitFinish();
 
 // This listener allows us to clear the default data for the selection added for the drag.
 var shouldClear = false;
 window.addEventListener("dragstart", function (event) { if (shouldClear) event.dataTransfer.clearData() }, true);
@@ -154,16 +155,27 @@ function doTest()
   synthesizeDrop(contenteditable.childNodes[4], contenteditable, [], "copy");
   is(contenteditable.childNodes.length, 7, "Move text/html and text/plain from contenteditable onto itself child nodes");
   is(contenteditable.childNodes[6].tagName, "I", "Move text/html and text/plain from contenteditable onto itself italic");
   is(contenteditable.childNodes[6].textContent, "Italic", "Move text/html and text/plain from contenteditable onto itself text");
 
   // We'd test 'move' here as well as 'copy', but that requires knowledge of
   // the source of the drag which drag simulation doesn't provide.
 
+  // -------- Test dragging non-editable nested inside contenteditable to contenteditable
+
+  input.focus(); // this resets some state in the selection otherwise an inexplicable error occurs calling selectAllChildren.
+  input.blur();
+
+  var nonEditable = document.getElementById("noneditable");
+  selection.selectAllChildren(nonEditable);
+  synthesizeDrop(nonEditable, document.getElementById("first"), [], "copy");
+  is(document.getElementById("nestedce").textContent, " MiddleFirst letter Middle Last part",
+     "Drag non-editable text/html onto contenteditable text");
+
   SimpleTest.finish();
 }
 
 SimpleTest.waitForFocus(doTest);
 
 </script>
 </body>
 </html>
--- a/editor/libeditor/html/nsHTMLDataTransfer.cpp
+++ b/editor/libeditor/html/nsHTMLDataTransfer.cpp
@@ -1366,27 +1366,25 @@ GetStringFromDataTransfer(nsIDOMDataTran
 
 nsresult nsHTMLEditor::InsertFromDataTransfer(nsIDOMDataTransfer *aDataTransfer,
                                               int32_t aIndex,
                                               nsIDOMDocument *aSourceDoc,
                                               nsIDOMNode *aDestinationNode,
                                               int32_t aDestOffset,
                                               bool aDoDeleteSelection)
 {
-  nsresult rv = NS_OK;
-
   nsCOMPtr<nsIDOMDOMStringList> types;
   aDataTransfer->MozTypesAt(aIndex, getter_AddRefs(types));
 
   bool hasPrivateHTMLFlavor;
   types->Contains(NS_LITERAL_STRING(kHTMLContext), &hasPrivateHTMLFlavor);
 
   bool isText = IsPlaintextEditor();
   bool isSafe = IsSafeToInsertData(aSourceDoc);
-  
+
   uint32_t length;
   types->GetLength(&length);
   for (uint32_t t = 0; t < length; t++) {
     nsAutoString type;
     types->Item(t, type);
 
     if (!isText) {
       if (type.EqualsLiteral(kFileMime) ||
@@ -1394,76 +1392,68 @@ nsresult nsHTMLEditor::InsertFromDataTra
           type.EqualsLiteral(kJPGImageMime) ||
           type.EqualsLiteral(kPNGImageMime) ||
           type.EqualsLiteral(kGIFImageMime)) {
         nsCOMPtr<nsIVariant> variant;
         aDataTransfer->MozGetDataAt(type, aIndex, getter_AddRefs(variant));
         if (variant) {
           nsCOMPtr<nsISupports> object;
           variant->GetAsISupports(getter_AddRefs(object));
-          rv = InsertObject(NS_ConvertUTF16toUTF8(type).get(), object, isSafe,
-                            aSourceDoc, aDestinationNode, aDestOffset, aDoDeleteSelection);
-          if (NS_SUCCEEDED(rv))
-            return NS_OK;
+          return InsertObject(NS_ConvertUTF16toUTF8(type).get(), object, isSafe,
+                              aSourceDoc, aDestinationNode, aDestOffset, aDoDeleteSelection);
         }
       }
       else if (!hasPrivateHTMLFlavor && type.EqualsLiteral(kNativeHTMLMime)) {
         nsAutoString text;
         GetStringFromDataTransfer(aDataTransfer, NS_LITERAL_STRING(kNativeHTMLMime), aIndex, text);
         NS_ConvertUTF16toUTF8 cfhtml(text);
 
         nsXPIDLString cfcontext, cffragment, cfselection; // cfselection left emtpy for now
 
-        rv = ParseCFHTML(cfhtml, getter_Copies(cffragment), getter_Copies(cfcontext));
+        nsresult rv = ParseCFHTML(cfhtml, getter_Copies(cffragment), getter_Copies(cfcontext));
         if (NS_SUCCEEDED(rv) && !cffragment.IsEmpty())
         {
           nsAutoEditBatch beginBatching(this);
-          rv = DoInsertHTMLWithContext(cffragment,
-                                       cfcontext, cfselection, type,
-                                       aSourceDoc,
-                                       aDestinationNode, aDestOffset,
-                                       aDoDeleteSelection,
-                                       isSafe);
-          if (NS_SUCCEEDED(rv))
-            return NS_OK;
+          return DoInsertHTMLWithContext(cffragment,
+                                         cfcontext, cfselection, type,
+                                         aSourceDoc,
+                                         aDestinationNode, aDestOffset,
+                                         aDoDeleteSelection,
+                                         isSafe);
         }
       }
       else if (type.EqualsLiteral(kHTMLMime)) {
         nsAutoString text, contextString, infoString;
         GetStringFromDataTransfer(aDataTransfer, type, aIndex, text);
         GetStringFromDataTransfer(aDataTransfer, NS_LITERAL_STRING(kHTMLContext), aIndex, contextString);
         GetStringFromDataTransfer(aDataTransfer, NS_LITERAL_STRING(kHTMLInfo), aIndex, infoString);
 
         nsAutoEditBatch beginBatching(this);
         if (type.EqualsLiteral(kHTMLMime)) {
-          rv = DoInsertHTMLWithContext(text,
-                                       contextString, infoString, type,
-                                       aSourceDoc,
-                                       aDestinationNode, aDestOffset,
-                                       aDoDeleteSelection,
-                                       isSafe);
-          if (NS_SUCCEEDED(rv))
-            return NS_OK;
+          return DoInsertHTMLWithContext(text,
+                                         contextString, infoString, type,
+                                         aSourceDoc,
+                                         aDestinationNode, aDestOffset,
+                                         aDoDeleteSelection,
+                                         isSafe);
         }
       }
     }
 
     if (type.EqualsLiteral(kTextMime) ||
         type.EqualsLiteral(kMozTextInternal)) {
       nsAutoString text;
       GetStringFromDataTransfer(aDataTransfer, type, aIndex, text);
 
       nsAutoEditBatch beginBatching(this);
-      rv = InsertTextAt(text, aDestinationNode, aDestOffset, aDoDeleteSelection);
-      if (NS_SUCCEEDED(rv))
-        return NS_OK;
+      return InsertTextAt(text, aDestinationNode, aDestOffset, aDoDeleteSelection);
     }
   }
 
-  return rv;
+  return NS_OK;
 }
 
 bool nsHTMLEditor::HavePrivateHTMLFlavor(nsIClipboard *aClipboard)
 {
   // check the clipboard for our special kHTMLContext flavor.  If that is there, we know
   // we have our own internal html format on clipboard.
 
   NS_ENSURE_TRUE(aClipboard, false);
--- a/gfx/gl/GLContext.h
+++ b/gfx/gl/GLContext.h
@@ -580,18 +580,17 @@ public:
         ContextFlagsMesaLLVMPipe = 0x2
     };
 
     enum GLContextType {
         ContextTypeUnknown,
         ContextTypeWGL,
         ContextTypeCGL,
         ContextTypeGLX,
-        ContextTypeEGL,
-        ContextTypeOSMesa
+        ContextTypeEGL
     };
 
     virtual GLContextType GetContextType() { return ContextTypeUnknown; }
 
     virtual bool MakeCurrentImpl(bool aForce = false) = 0;
 
 #ifdef DEBUG
     static void StaticInit() {
--- a/gfx/gl/GLContextProvider.h
+++ b/gfx/gl/GLContextProvider.h
@@ -14,25 +14,21 @@
 class nsIWidget;
 class gfxASurface;
 
 namespace mozilla {
 namespace gl {
 
 #define IN_GL_CONTEXT_PROVIDER_H
 
-// Null and OSMesa are always there
+// Null is always there
 #define GL_CONTEXT_PROVIDER_NAME GLContextProviderNull
 #include "GLContextProviderImpl.h"
 #undef GL_CONTEXT_PROVIDER_NAME
 
-#define GL_CONTEXT_PROVIDER_NAME GLContextProviderOSMesa
-#include "GLContextProviderImpl.h"
-#undef GL_CONTEXT_PROVIDER_NAME
-
 #ifdef XP_WIN
 #define GL_CONTEXT_PROVIDER_NAME GLContextProviderWGL
 #include "GLContextProviderImpl.h"
 #undef GL_CONTEXT_PROVIDER_NAME
 #define GL_CONTEXT_PROVIDER_DEFAULT GLContextProviderWGL
 #define DEFAULT_IMPL WGL
 #endif
 
deleted file mode 100644
--- a/gfx/gl/GLContextProviderOSMesa.cpp
+++ /dev/null
@@ -1,266 +0,0 @@
-/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
- * 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/. */
-
-#include "GLContextProvider.h"
-#include "GLContext.h"
-#include "GLLibraryLoader.h"
-#include "nsDebug.h"
-#include "nsString.h"
-#include "nsIWidget.h"
-#include "nsDirectoryServiceUtils.h"
-#include "nsAppDirectoryServiceDefs.h"
-#include "nsIConsoleService.h"
-#include "mozilla/Preferences.h"
-#include "gfxASurface.h"
-#include "gfxImageSurface.h"
-
-#include "gfxCrashReporterUtils.h"
-
-// from GL/osmesa.h. We don't include that file so as to avoid having a build-time dependency on OSMesa.
-#define OSMESA_RGBA     GL_RGBA
-#define OSMESA_BGRA     0x1
-#define OSMESA_ARGB     0x2
-#define OSMESA_RGB      GL_RGB
-#define OSMESA_BGR      0x4
-#define OSMESA_RGB_565  0x5
-#define OSMESA_Y_UP     0x11
-
-namespace mozilla {
-namespace gl {
-
-static void LogMessage(const char *msg)
-{
-  nsCOMPtr<nsIConsoleService> console(do_GetService(NS_CONSOLESERVICE_CONTRACTID));
-  if (console) {
-    console->LogStringMessage(NS_ConvertUTF8toUTF16(nsDependentCString(msg)).get());
-    fprintf(stderr, "%s\n", msg);
-  }
-}
-
-typedef void* PrivateOSMesaContext;
-
-class OSMesaLibrary
-{
-public:
-    OSMesaLibrary() : mInitialized(false), mOSMesaLibrary(nullptr) {}
-
-    typedef PrivateOSMesaContext (GLAPIENTRY * PFNOSMESACREATECONTEXTEXT) (GLenum, GLint, GLint, GLint, PrivateOSMesaContext);
-    typedef void (GLAPIENTRY * PFNOSMESADESTROYCONTEXT) (PrivateOSMesaContext);
-    typedef bool (GLAPIENTRY * PFNOSMESAMAKECURRENT) (PrivateOSMesaContext, void *, GLenum, GLsizei, GLsizei);
-    typedef PrivateOSMesaContext (GLAPIENTRY * PFNOSMESAGETCURRENTCONTEXT) (void);
-    typedef void (GLAPIENTRY * PFNOSMESAPIXELSTORE) (GLint, GLint);
-    typedef PRFuncPtr (GLAPIENTRY * PFNOSMESAGETPROCADDRESS) (const char*);
-
-    PFNOSMESACREATECONTEXTEXT fCreateContextExt;
-    PFNOSMESADESTROYCONTEXT fDestroyContext;
-    PFNOSMESAMAKECURRENT fMakeCurrent;
-    PFNOSMESAGETCURRENTCONTEXT fGetCurrentContext;
-    PFNOSMESAPIXELSTORE fPixelStore;
-    PFNOSMESAGETPROCADDRESS fGetProcAddress;
-
-    bool EnsureInitialized();
-
-private:
-    bool mInitialized;
-    PRLibrary *mOSMesaLibrary;
-};
-
-OSMesaLibrary sOSMesaLibrary;
-
-bool
-OSMesaLibrary::EnsureInitialized()
-{
-    if (mInitialized)
-        return true;
-
-    nsAdoptingCString osmesalib = Preferences::GetCString("webgl.osmesalib");
-    if (osmesalib.IsEmpty()) {
-        return false;
-    }
-
-    mOSMesaLibrary = PR_LoadLibrary(osmesalib.get());
-
-    if (!mOSMesaLibrary) {
-        LogMessage("Couldn't open OSMesa lib for software rendering -- webgl.osmesalib path is incorrect, or not a valid shared library");
-        return false;
-    }
-
-    GLLibraryLoader::SymLoadStruct symbols[] = {
-        { (PRFuncPtr*) &fCreateContextExt, { "OSMesaCreateContextExt", NULL } },
-        { (PRFuncPtr*) &fMakeCurrent, { "OSMesaMakeCurrent", NULL } },
-        { (PRFuncPtr*) &fPixelStore, { "OSMesaPixelStore", NULL } },
-        { (PRFuncPtr*) &fDestroyContext, { "OSMesaDestroyContext", NULL } },
-        { (PRFuncPtr*) &fGetCurrentContext, { "OSMesaGetCurrentContext", NULL } },
-        { (PRFuncPtr*) &fMakeCurrent, { "OSMesaMakeCurrent", NULL } },
-        { (PRFuncPtr*) &fGetProcAddress, { "OSMesaGetProcAddress", NULL } },
-        { NULL, { NULL } }
-    };
-
-    if (!GLLibraryLoader::LoadSymbols(mOSMesaLibrary, &symbols[0])) {
-        LogMessage("Couldn't find required entry points in OSMesa libary");
-        return false;
-    }
-
-    mInitialized = true;
-    return true;
-}
-
-class GLContextOSMesa : public GLContext
-{
-public:
-    GLContextOSMesa(const ContextFormat& aFormat)
-        : GLContext(aFormat, true, nullptr),
-          mThebesSurface(nullptr),
-          mContext(nullptr)
-    {
-    }
-
-    ~GLContextOSMesa()
-    {
-        MarkDestroyed();
-
-        if (mContext)
-            sOSMesaLibrary.fDestroyContext(mContext);
-    }
-
-    GLContextType GetContextType() {
-        return ContextTypeOSMesa;
-    }
-
-    bool Init(const gfxIntSize &aSize)
-    {
-        int osmesa_format = -1;
-        int gfxasurface_imageformat = -1;
-        bool format_accepted = false;
-
-        if (mCreationFormat.red > 0 &&
-            mCreationFormat.green > 0 &&
-            mCreationFormat.blue > 0 &&
-            mCreationFormat.red <= 8 &&
-            mCreationFormat.green <= 8 &&
-            mCreationFormat.blue <= 8)
-        {
-            if (mCreationFormat.alpha == 0) {
-                // we can't use OSMESA_BGR because it is packed 24 bits per pixel.
-                // So we use OSMESA_BGRA and have to use ImageFormatRGB24
-                // to make sure that the dummy alpha channel is ignored.
-                osmesa_format = OSMESA_BGRA;
-                gfxasurface_imageformat = gfxASurface::ImageFormatRGB24;
-                format_accepted = true;
-            } else if (mCreationFormat.alpha <= 8) {
-                osmesa_format = OSMESA_BGRA;
-                gfxasurface_imageformat = gfxASurface::ImageFormatARGB32;
-                format_accepted = true;
-            }
-        }
-        if (!format_accepted) {
-            NS_WARNING("Pixel format not supported with OSMesa.");
-            return false;
-        }
-
-        mThebesSurface = new gfxImageSurface(aSize, gfxASurface::gfxImageFormat(gfxasurface_imageformat));
-        if (mThebesSurface->CairoStatus() != 0) {
-            NS_WARNING("image surface failed");
-            return false;
-        }
-
-        mContext = sOSMesaLibrary.fCreateContextExt(osmesa_format, mCreationFormat.depth, mCreationFormat.stencil, 0, NULL);
-        if (!mContext) {
-            NS_WARNING("OSMesaCreateContextExt failed!");
-            return false;
-        }
-
-        if (!MakeCurrent()) return false;
-        if (!SetupLookupFunction()) return false;
-
-        // OSMesa's different from the other GL providers, it renders to an image surface, not to a pbuffer
-        sOSMesaLibrary.fPixelStore(OSMESA_Y_UP, 0);
-
-        return InitWithPrefix("gl", true);
-    }
-
-    bool MakeCurrentImpl(bool aForce = false)
-    {
-        bool succeeded
-          = sOSMesaLibrary.fMakeCurrent(mContext, mThebesSurface->Data(),
-                                        LOCAL_GL_UNSIGNED_BYTE,
-                                        mThebesSurface->Width(),
-                                        mThebesSurface->Height());
-        NS_ASSERTION(succeeded, "Failed to make OSMesa context current!");
-
-        return succeeded;
-    }
-
-    virtual bool IsCurrent() {
-        return sOSMesaLibrary.fGetCurrentContext() == mContext;
-    }
-
-    bool SetupLookupFunction()
-    {
-        mLookupFunc = (PlatformLookupFunction)sOSMesaLibrary.fGetProcAddress;
-        return true;
-    }
-
-    void *GetNativeData(NativeDataType aType)
-    {
-        switch (aType) {
-        case NativeImageSurface:
-            return mThebesSurface.get();
-        default:
-            return nullptr;
-        }
-    }
-
-    bool SupportsRobustness()
-    {
-        return false;
-    }
-
-private:
-    nsRefPtr<gfxImageSurface> mThebesSurface;
-    PrivateOSMesaContext mContext;
-};
-
-already_AddRefed<GLContext>
-GLContextProviderOSMesa::CreateForWindow(nsIWidget *aWidget)
-{
-    return nullptr;
-}
-
-already_AddRefed<GLContext>
-GLContextProviderOSMesa::CreateOffscreen(const gfxIntSize& aSize,
-                                         const ContextFormat& aFormat,
-                                         const ContextFlags)
-{
-    if (!sOSMesaLibrary.EnsureInitialized()) {
-        return nullptr;
-    }
-
-    ContextFormat actualFormat(aFormat);
-    actualFormat.samples = 0;
-
-    nsRefPtr<GLContextOSMesa> glContext = new GLContextOSMesa(actualFormat);
-
-    if (!glContext->Init(aSize))
-    {
-        return nullptr;
-    }
-
-    return glContext.forget();
-}
-
-GLContext *
-GLContextProviderOSMesa::GetGlobalContext(const ContextFlags)
-{
-    return nullptr;
-}
-
-void
-GLContextProviderOSMesa::Shutdown()
-{
-}
-
-} /* namespace gl */
-} /* namespace mozilla */
--- a/gfx/gl/Makefile.in
+++ b/gfx/gl/Makefile.in
@@ -42,17 +42,16 @@ DEFINES += -DMOZ_D3DX9_DLL=$(MOZ_D3DX9_D
 DEFINES += -DMOZ_D3DCOMPILER_DLL=$(MOZ_D3DCOMPILER_DLL)
 endif
 endif
 
 CPPSRCS	= \
 	GLContext.cpp \
 	GLContextUtils.cpp \
 	GLLibraryLoader.cpp \
-	GLContextProviderOSMesa.cpp \
 	$(NULL)
 
 GL_PROVIDER = Null
 
 ifeq ($(MOZ_WIDGET_TOOLKIT),windows)
 GL_PROVIDER = WGL
 endif
 
--- a/gfx/layers/ImageContainer.cpp
+++ b/gfx/layers/ImageContainer.cpp
@@ -407,36 +407,36 @@ PlanarYCbCrImage::~PlanarYCbCrImage()
 
 uint8_t* 
 PlanarYCbCrImage::AllocateBuffer(uint32_t aSize)
 {
   return mRecycleBin->GetBuffer(aSize); 
 }
 
 static void
-CopyPlane(uint8_t *aDst, uint8_t *aSrc,
+CopyPlane(uint8_t *aDst, const uint8_t *aSrc,
           const gfxIntSize &aSize, int32_t aStride, int32_t aSkip)
 {
   if (!aSkip) {
     // Fast path: planar input.
     memcpy(aDst, aSrc, aSize.height * aStride);
   } else {
     int32_t height = aSize.height;
     int32_t width = aSize.width;
     for (int y = 0; y < height; ++y) {
-      uint8_t *src = aSrc;
+      const uint8_t *src = aSrc;
       uint8_t *dst = aDst;
       // Slow path
       for (int x = 0; x < width; ++x) {
         *dst++ = *src++;
         src += aSkip;
       }
+      aSrc += aStride;
+      aDst += aStride;
     }
-    aSrc += aStride;
-    aDst += aStride;
   }
 }
 
 void
 PlanarYCbCrImage::CopyData(const Data& aData)
 {
   mData = aData;
 
--- a/gfx/layers/d3d10/LayerManagerD3D10.cpp
+++ b/gfx/layers/d3d10/LayerManagerD3D10.cpp
@@ -239,17 +239,17 @@ LayerManagerD3D10::Initialize(bool force
 
     /**
      * Create a swap chain, this swap chain will contain the backbuffer for
      * the window we draw to. The front buffer is the full screen front
      * buffer.
     */
     nsRefPtr<IDXGISwapChain1> swapChain1;
     hr = dxgiFactory->CreateSwapChainForCoreWindow(
-           dxgiDevice, (IUnknown *)mWidget->GetNativeData(NS_NATIVE_WINDOW),
+           dxgiDevice, (IUnknown *)mWidget->GetNativeData(NS_NATIVE_ICOREWINDOW),
            &swapDesc, nullptr, getter_AddRefs(swapChain1));
     if (FAILED(hr)) {
         return false;
     }
     mSwapChain = swapChain1;
   } else
 #endif
   {
--- a/gfx/thebes/gfxColor.h
+++ b/gfx/thebes/gfxColor.h
@@ -92,35 +92,35 @@
 #define GFX_DIVIDE_BY_255(v)  \
      (((((unsigned)(v)) << 8) + ((unsigned)(v)) + 255) >> 16)
 
 /**
  * Fast premultiply
  *
  * equivalent to (((c)*(a))/255)
  */
-PRUint8 MOZ_ALWAYS_INLINE gfxPreMultiply(PRUint8 c, PRUint8 a) {
+uint8_t MOZ_ALWAYS_INLINE gfxPreMultiply(uint8_t c, uint8_t a) {
     return GFX_DIVIDE_BY_255((c)*(a));
 }
 
 /**
  * Pack the 4 8-bit channels (A,R,G,B)
  * into a 32-bit packed NON-premultiplied pixel.
  */
-PRUint32 MOZ_ALWAYS_INLINE
-gfxPackedPixelNoPreMultiply(PRUint8 a, PRUint8 r, PRUint8 g, PRUint8 b) {
+uint32_t MOZ_ALWAYS_INLINE
+gfxPackedPixelNoPreMultiply(uint8_t a, uint8_t r, uint8_t g, uint8_t b) {
     return (((a) << 24) | ((r) << 16) | ((g) << 8) | (b));
 }
 
 /**
  * Pack the 4 8-bit channels (A,R,G,B)
  * into a 32-bit packed premultiplied pixel.
  */
-PRUint32 MOZ_ALWAYS_INLINE
-gfxPackedPixel(PRUint8 a, PRUint8 r, PRUint8 g, PRUint8 b) {
+uint32_t MOZ_ALWAYS_INLINE
+gfxPackedPixel(uint8_t a, uint8_t r, uint8_t g, uint8_t b) {
     if (a == 0x00)
         return 0x00000000;
     else if (a == 0xFF) {
         return gfxPackedPixelNoPreMultiply(a, r, g, b);
     } else {
         return  ((a) << 24) |
                 (gfxPreMultiply(r,a) << 16) |
                 (gfxPreMultiply(g,a) << 8)  |
--- a/gfx/thebes/gfxPlatform.cpp
+++ b/gfx/thebes/gfxPlatform.cpp
@@ -385,19 +385,16 @@ gfxPlatform::Shutdown()
 #ifdef MOZ_WIDGET_ANDROID
     // Shut down the texture pool
     mozilla::gl::TexturePoolOGL::Shutdown();
 #endif
 
     // Shut down the default GL context provider.
     mozilla::gl::GLContextProvider::Shutdown();
 
-    // We always have OSMesa at least potentially available; shut it down too.
-    mozilla::gl::GLContextProviderOSMesa::Shutdown();
-
 #if defined(XP_WIN)
     // The above shutdown calls operate on the available context providers on
     // most platforms.  Windows is a "special snowflake", though, and has three
     // context providers available, so we have to shut all of them down.
     // We should only support the default GL provider on Windows; then, this
     // could go away. Unfortunately, we currently support WGL (the default) for
     // WebGL on Optimus.
     mozilla::gl::GLContextProviderEGL::Shutdown();
--- a/js/src/Makefile.in
+++ b/js/src/Makefile.in
@@ -149,18 +149,16 @@ CPPSRCS		= \
 # browser builds.  Don't add new files here unless you know what you're
 # doing!
 INSTALLED_HEADERS = \
 		js-config.h \
 		jscpucfg.h \
 		js.msg \
 		jsalloc.h \
 		jsapi.h \
-		jsatom.h \
-		jsatom.tbl \
 		jsclass.h \
 		jsclist.h \
 		jsdbgapi.h \
 		jsdhash.h \
 		jsfriendapi.h \
 		jsgc.h \
 		jslock.h \
 		json.h \
--- a/js/src/builtin/ParallelArray.cpp
+++ b/js/src/builtin/ParallelArray.cpp
@@ -855,17 +855,17 @@ ParallelArrayObject::initClass(JSContext
         !DefineConstructorAndPrototype(cx, global, key, ctor, proto))
     {
         return NULL;
     }
 
     // Define the length and shape properties.
     RootedId lengthId(cx, AtomToId(cx->runtime->atomState.lengthAtom));
     RootedId shapeId(cx, AtomToId(cx->runtime->atomState.shapeAtom));
-    unsigned flags = JSPROP_PERMANENT | JSPROP_READONLY | JSPROP_SHARED | JSPROP_GETTER;
+    unsigned flags = JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_GETTER;
 
     JSObject *scriptedLength = js_NewFunction(cx, NULL, NonGenericMethod<lengthGetter>,
                                               0, 0, global, NULL);
     JSObject *scriptedShape = js_NewFunction(cx, NULL, NonGenericMethod<dimensionsGetter>,
                                              0, 0, global, NULL);
 
     RootedValue value(cx, UndefinedValue());
     if (!scriptedLength || !scriptedShape ||
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -901,16 +901,20 @@ JSRuntime::init(uint32_t maxbytes)
 #endif
 
     JS::TlsRuntime.set(this);
 
 #ifdef JS_METHODJIT_SPEW
     JMCheckLogging();
 #endif
 
+#if defined(JSGC_ROOT_ANALYSIS) || defined(JSGC_USE_EXACT_ROOTING)
+    PodArrayZero(thingGCRooters);
+#endif
+
     if (!js_InitGC(this, maxbytes))
         return false;
 
     if (!gcMarker.init())
         return false;
 
     const char *size = getenv("JSGC_MARK_STACK_LIMIT");
     if (size)
--- a/js/src/jsatom.h
+++ b/js/src/jsatom.h
@@ -3,134 +3,56 @@
  * 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/. */
 
 #ifndef jsatom_h___
 #define jsatom_h___
 
 #include <stddef.h>
-#include "jsversion.h"
 #include "jsalloc.h"
 #include "jsapi.h"
+#include "jsfriendapi.h"
 #include "jsprvtd.h"
 #include "jspubtd.h"
 #include "jslock.h"
+#include "jsversion.h"
 
 #include "gc/Barrier.h"
 #include "js/HashTable.h"
 #include "mozilla/HashFunctions.h"
 
 struct JSIdArray {
     int length;
     js::HeapId vector[1];    /* actually, length jsid words */
 };
 
-/* Engine-internal extensions of jsid */
-
-static JS_ALWAYS_INLINE jsid
-JSID_FROM_BITS(size_t bits)
-{
-    jsid id;
-    JSID_BITS(id) = bits;
-    return id;
-}
+namespace js {
 
-/*
- * Must not be used on atoms that are representable as integer jsids.
- * Prefer NameToId or AtomToId over this function:
- *
- * A PropertyName is an atom that does not contain an integer in the range
- * [0, UINT32_MAX]. However, jsid can only hold an integer in the range
- * [0, JSID_INT_MAX] (where JSID_INT_MAX == 2^31-1).  Thus, for the range of
- * integers (JSID_INT_MAX, UINT32_MAX], to represent as a jsid 'id', it must be
- * the case JSID_IS_ATOM(id) and !JSID_TO_ATOM(id)->isPropertyName().  In most
- * cases when creating a jsid, code does not have to care about this corner
- * case because:
- *
- * - When given an arbitrary JSAtom*, AtomToId must be used, which checks for
- *   integer atoms representable as integer jsids, and does this conversion.
- *
- * - When given a PropertyName*, NameToId can be used which which does not need
- *   to do any dynamic checks.
- *
- * Thus, it is only the rare third case which needs this function, which
- * handles any JSAtom* that is known not to be representable with an int jsid.
- */
-static JS_ALWAYS_INLINE jsid
-NON_INTEGER_ATOM_TO_JSID(JSAtom *atom)
-{
-    JS_ASSERT(((size_t)atom & 0x7) == 0);
-    jsid id = JSID_FROM_BITS((size_t)atom);
-    JS_ASSERT(id == INTERNED_STRING_TO_JSID(NULL, (JSString*)atom));
-    return id;
-}
-
-/* All strings stored in jsids are atomized, but are not necessarily property names. */
-static JS_ALWAYS_INLINE JSBool
-JSID_IS_ATOM(jsid id)
-{
-    return JSID_IS_STRING(id);
-}
-
-static JS_ALWAYS_INLINE JSBool
-JSID_IS_ATOM(jsid id, JSAtom *atom)
-{
-    return id == JSID_FROM_BITS((size_t)atom);
-}
-
-static JS_ALWAYS_INLINE JSAtom *
-JSID_TO_ATOM(jsid id)
-{
-    return (JSAtom *)JSID_TO_STRING(id);
-}
-
-JS_STATIC_ASSERT(sizeof(js::HashNumber) == 4);
-JS_STATIC_ASSERT(sizeof(jsid) == JS_BYTES_PER_WORD);
-
-namespace js {
+JS_STATIC_ASSERT(sizeof(HashNumber) == 4);
 
 static JS_ALWAYS_INLINE js::HashNumber
 HashId(jsid id)
 {
     return HashGeneric(JSID_BITS(id));
 }
 
-static JS_ALWAYS_INLINE Value
-IdToValue(jsid id)
-{
-    if (JSID_IS_STRING(id))
-        return StringValue(JSID_TO_STRING(id));
-    if (JS_LIKELY(JSID_IS_INT(id)))
-        return Int32Value(JSID_TO_INT(id));
-    if (JS_LIKELY(JSID_IS_OBJECT(id)))
-        return ObjectValue(*JSID_TO_OBJECT(id));
-    JS_ASSERT(JSID_IS_DEFAULT_XML_NAMESPACE(id) || JSID_IS_VOID(id));
-    return UndefinedValue();
-}
-
-static JS_ALWAYS_INLINE jsval
-IdToJsval(jsid id)
-{
-    return IdToValue(id);
-}
-
 template<>
 struct DefaultHasher<jsid>
 {
     typedef jsid Lookup;
     static HashNumber hash(const Lookup &l) {
         return HashNumber(JSID_BITS(l));
     }
     static bool match(const jsid &id, const Lookup &l) {
         return id == l;
     }
 };
 
-}
+} /* namespace js */
 
 /*
  * Return a printable, lossless char[] representation of a string-type atom.
  * The lifetime of the result matches the lifetime of bytes.
  */
 extern const char *
 js_AtomToPrintableString(JSContext *cx, JSAtom *atom, JSAutoByteString *bytes);
 
--- a/js/src/jsfriendapi.h
+++ b/js/src/jsfriendapi.h
@@ -1389,9 +1389,100 @@ SET_JITINFO(JSFunction * func, const JSJ
 {
     js::shadow::Function *fun = reinterpret_cast<js::shadow::Function *>(func);
     /* JS_ASSERT(func->isNative()). 0x4000 is JSFUN_INTERPRETED */
     JS_ASSERT(!(fun->flags & 0x4000));
     fun->jitinfo = info;
 }
 #endif /* __cplusplus */
 
+/*
+ * Engine-internal extensions of jsid.  This code is here only until we
+ * eliminate Gecko's dependencies on it!
+ */
+
+static JS_ALWAYS_INLINE jsid
+JSID_FROM_BITS(size_t bits)
+{
+    jsid id;
+    JSID_BITS(id) = bits;
+    return id;
+}
+
+/*
+ * Must not be used on atoms that are representable as integer jsids.
+ * Prefer NameToId or AtomToId over this function:
+ *
+ * A PropertyName is an atom that does not contain an integer in the range
+ * [0, UINT32_MAX]. However, jsid can only hold an integer in the range
+ * [0, JSID_INT_MAX] (where JSID_INT_MAX == 2^31-1).  Thus, for the range of
+ * integers (JSID_INT_MAX, UINT32_MAX], to represent as a jsid 'id', it must be
+ * the case JSID_IS_ATOM(id) and !JSID_TO_ATOM(id)->isPropertyName().  In most
+ * cases when creating a jsid, code does not have to care about this corner
+ * case because:
+ *
+ * - When given an arbitrary JSAtom*, AtomToId must be used, which checks for
+ *   integer atoms representable as integer jsids, and does this conversion.
+ *
+ * - When given a PropertyName*, NameToId can be used which which does not need
+ *   to do any dynamic checks.
+ *
+ * Thus, it is only the rare third case which needs this function, which
+ * handles any JSAtom* that is known not to be representable with an int jsid.
+ */
+static JS_ALWAYS_INLINE jsid
+NON_INTEGER_ATOM_TO_JSID(JSAtom *atom)
+{
+    JS_ASSERT(((size_t)atom & 0x7) == 0);
+    jsid id = JSID_FROM_BITS((size_t)atom);
+    JS_ASSERT(id == INTERNED_STRING_TO_JSID(NULL, (JSString*)atom));
+    return id;
+}
+
+/* All strings stored in jsids are atomized, but are not necessarily property names. */
+static JS_ALWAYS_INLINE JSBool
+JSID_IS_ATOM(jsid id)
+{
+    return JSID_IS_STRING(id);
+}
+
+static JS_ALWAYS_INLINE JSBool
+JSID_IS_ATOM(jsid id, JSAtom *atom)
+{
+    return id == JSID_FROM_BITS((size_t)atom);
+}
+
+static JS_ALWAYS_INLINE JSAtom *
+JSID_TO_ATOM(jsid id)
+{
+    return (JSAtom *)JSID_TO_STRING(id);
+}
+
+JS_STATIC_ASSERT(sizeof(jsid) == JS_BYTES_PER_WORD);
+
+#ifdef __cplusplus
+
+namespace js {
+
+static JS_ALWAYS_INLINE Value
+IdToValue(jsid id)
+{
+    if (JSID_IS_STRING(id))
+        return StringValue(JSID_TO_STRING(id));
+    if (JS_LIKELY(JSID_IS_INT(id)))
+        return Int32Value(JSID_TO_INT(id));
+    if (JS_LIKELY(JSID_IS_OBJECT(id)))
+        return ObjectValue(*JSID_TO_OBJECT(id));
+    JS_ASSERT(JSID_IS_DEFAULT_XML_NAMESPACE(id) || JSID_IS_VOID(id));
+    return UndefinedValue();
+}
+
+static JS_ALWAYS_INLINE jsval
+IdToJsval(jsid id)
+{
+    return IdToValue(id);
+}
+
+} /* namespace js */
+
+#endif /* __cplusplus */
+
 #endif /* jsfriendapi_h___ */
--- a/js/xpconnect/src/XPCQuickStubs.cpp
+++ b/js/xpconnect/src/XPCQuickStubs.cpp
@@ -1,17 +1,16 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /* 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/. */
 
 #include "mozilla/Util.h"
 
 #include "jsapi.h"
-#include "jsatom.h"
 #include "jsfriendapi.h"
 #include "nsCOMPtr.h"
 #include "xpcprivate.h"
 #include "XPCInlines.h"
 #include "XPCQuickStubs.h"
 #include "XPCWrapper.h"
 #include "mozilla/dom/BindingUtils.h"
 
--- a/js/xpconnect/src/XPCQuickStubs.h
+++ b/js/xpconnect/src/XPCQuickStubs.h
@@ -6,18 +6,16 @@
 
 #ifndef xpcquickstubs_h___
 #define xpcquickstubs_h___
 
 #include "xpcpublic.h"
 #include "xpcprivate.h"
 #include "qsObjectHelper.h"
 
-#include "jsatom.h"
-
 /* XPCQuickStubs.h - Support functions used only by quick stubs. */
 
 class XPCCallContext;
 
 #define XPC_QS_NULL_INDEX  ((uint16_t) -1)
 
 struct xpc_qsPropertySpec {
     uint16_t name_index;
--- a/js/xpconnect/src/dombindings.cpp
+++ b/js/xpconnect/src/dombindings.cpp
@@ -14,17 +14,16 @@
 #include "XPCWrapper.h"
 #include "WrapperFactory.h"
 #include "nsDOMClassInfo.h"
 #include "nsGlobalWindow.h"
 #include "nsWrapperCacheInlines.h"
 #include "mozilla/dom/BindingUtils.h"
 
 #include "jsapi.h"
-#include "jsatom.h"
 
 using namespace JS;
 using namespace mozilla::dom;
 
 namespace mozilla {
 namespace dom {
 namespace oldproxybindings {
 
--- a/js/xpconnect/src/nsXPConnect.cpp
+++ b/js/xpconnect/src/nsXPConnect.cpp
@@ -9,17 +9,16 @@
 #include "mozilla/Assertions.h"
 #include "mozilla/Base64.h"
 #include "mozilla/Util.h"
 
 #include "xpcprivate.h"
 #include "XPCWrapper.h"
 #include "nsBaseHashtable.h"
 #include "nsHashKeys.h"
-#include "jsatom.h"
 #include "jsfriendapi.h"
 #include "jsgc.h"
 #include "dom_quickstubs.h"
 #include "nsNullPrincipal.h"
 #include "nsIURI.h"
 #include "nsJSEnvironment.h"
 #include "nsThreadUtils.h"
 
--- a/layout/base/nsCSSFrameConstructor.cpp
+++ b/layout/base/nsCSSFrameConstructor.cpp
@@ -8036,17 +8036,17 @@ nsCSSFrameConstructor::ProcessRestyledFr
 
   while (0 <= --index) {
     nsIFrame* frame;
     nsIContent* content;
     bool didReflowThisFrame = false;
     nsChangeHint hint;
     aChangeList.ChangeAt(index, frame, content, hint);
 
-    NS_ASSERTION(!(hint & nsChangeHint_ReflowFrame) ||
+    NS_ASSERTION(!(hint & nsChangeHint_AllReflowHints) ||
                  (hint & nsChangeHint_NeedReflow),
                  "Reflow hint bits set without actually asking for a reflow");
 
     if (frame && frame->GetContent() != content) {
       // XXXbz this is due to image maps messing with the primary frame of
       // <area>s.  See bug 135040.  Remove this block once that's fixed.
       frame = nullptr;
       if (!(hint & nsChangeHint_ReconstructFrame)) {
--- a/layout/base/nsChangeHint.h
+++ b/layout/base/nsChangeHint.h
@@ -207,23 +207,23 @@ inline nsChangeHint NS_HintsNotHandledFo
   return result;
 }
 
 // Redefine the old NS_STYLE_HINT constants in terms of the new hint structure
 #define NS_STYLE_HINT_NONE \
   nsChangeHint(0)
 #define NS_STYLE_HINT_VISUAL \
   nsChangeHint(nsChangeHint_RepaintFrame | nsChangeHint_SyncFrameView)
-#define nsChangeHint_ReflowFrame                        \
+#define nsChangeHint_AllReflowHints                     \
   nsChangeHint(nsChangeHint_NeedReflow |                \
                nsChangeHint_ClearAncestorIntrinsics |   \
                nsChangeHint_ClearDescendantIntrinsics | \
                nsChangeHint_NeedDirtyReflow)
 #define NS_STYLE_HINT_REFLOW \
-  nsChangeHint(NS_STYLE_HINT_VISUAL | nsChangeHint_ReflowFrame)
+  nsChangeHint(NS_STYLE_HINT_VISUAL | nsChangeHint_AllReflowHints)
 #define NS_STYLE_HINT_FRAMECHANGE \
   nsChangeHint(NS_STYLE_HINT_REFLOW | nsChangeHint_ReconstructFrame)
 
 /**
  * |nsRestyleHint| is a bitfield for the result of
  * |HasStateDependentStyle| and |HasAttributeDependentStyle|.  When no
  * restyling is necessary, use |nsRestyleHint(0)|.
  */
--- a/layout/base/nsFrameManager.cpp
+++ b/layout/base/nsFrameManager.cpp
@@ -979,17 +979,17 @@ CaptureChange(nsStyleContext* aOldContex
               nsStyleChangeList* aChangeList,
               /*inout*/nsChangeHint &aMinChange,
               /*in*/nsChangeHint aParentHintsNotHandledForDescendants,
               /*out*/nsChangeHint &aHintsNotHandledForDescendants,
               nsChangeHint aChangeToAssume)
 {
   nsChangeHint ourChange = aOldContext->CalcStyleDifference(aNewContext,
                              aParentHintsNotHandledForDescendants);
-  NS_ASSERTION(!(ourChange & nsChangeHint_ReflowFrame) ||
+  NS_ASSERTION(!(ourChange & nsChangeHint_AllReflowHints) ||
                (ourChange & nsChangeHint_NeedReflow),
                "Reflow hint bits set without actually asking for a reflow");
 
   NS_UpdateHint(ourChange, aChangeToAssume);
   if (NS_UpdateHint(aMinChange, ourChange)) {
     if (!(ourChange & nsChangeHint_ReconstructFrame) || aContent) {
       aChangeList->AppendChange(aFrame, aContent, ourChange);
     }
@@ -1544,32 +1544,32 @@ nsFrameManager::ReResolveStyleContext(ns
               nsIFrame* outOfFlowFrame =
                 nsPlaceholderFrame::GetRealFrameForPlaceholder(child);
               NS_ASSERTION(outOfFlowFrame, "no out-of-flow frame");
               NS_ASSERTION(outOfFlowFrame != resolvedChild,
                            "out-of-flow frame not a true descendant");
 
               // Note that the out-of-flow may not be a geometric descendant of
               // the frame where we started the reresolve.  Therefore, even if
-              // aMinChange already includes nsChangeHint_ReflowFrame we don't
+              // aMinChange already includes nsChangeHint_AllReflowHints we don't
               // want to pass that on to the out-of-flow reresolve, since that
               // can lead to the out-of-flow not getting reflowed when it should
               // be (eg a reresolve starting at <body> that involves reflowing
               // the <body> would miss reflowing fixed-pos nodes that also need
               // reflow).  In the cases when the out-of-flow _is_ a geometric
               // descendant of a frame we already have a reflow hint for,
               // reflow coalescing should keep us from doing the work twice.
 
               // |nsFrame::GetParentStyleContextFrame| checks being out
               // of flow so that this works correctly.
               do {
                 ReResolveStyleContext(aPresContext, outOfFlowFrame,
                                       content, aChangeList,
                                       NS_SubtractHint(aMinChange,
-                                                      nsChangeHint_ReflowFrame),
+                                                      nsChangeHint_AllReflowHints),
                                       nonInheritedHints,
                                       childRestyleHint,
                                       aRestyleTracker,
                                       kidsDesiredA11yNotification,
                                       aVisibleKidsOfHiddenElement,
                                       aTreeMatchContext);
               } while ((outOfFlowFrame = outOfFlowFrame->GetNextContinuation()));
 
--- a/layout/base/nsStyleChangeList.cpp
+++ b/layout/base/nsStyleChangeList.cpp
@@ -58,17 +58,17 @@ nsStyleChangeList::AppendChange(nsIFrame
 {
   NS_ASSERTION(aFrame || (aHint & nsChangeHint_ReconstructFrame),
                "must have frame");
   NS_ASSERTION(aContent || !(aHint & nsChangeHint_ReconstructFrame),
                "must have content");
   // XXXbz we should make this take Element instead of nsIContent
   NS_ASSERTION(!aContent || aContent->IsElement(),
                "Shouldn't be trying to restyle non-elements directly");
-  NS_ASSERTION(!(aHint & nsChangeHint_ReflowFrame) ||
+  NS_ASSERTION(!(aHint & nsChangeHint_AllReflowHints) ||
                (aHint & nsChangeHint_NeedReflow),
                "Reflow hint bits set without actually asking for a reflow");
 
   if ((0 < mCount) && (aHint & nsChangeHint_ReconstructFrame)) { // filter out all other changes for same content
     if (aContent) {
       for (int32_t index = mCount - 1; index >= 0; --index) {
         if (aContent == mArray[index].mContent) { // remove this change
           aContent->Release();
--- a/layout/generic/nsInlineFrame.cpp
+++ b/layout/generic/nsInlineFrame.cpp
@@ -292,16 +292,19 @@ nsInlineFrame::Reflow(nsPresContext*    
                       const nsHTMLReflowState& aReflowState,
                       nsReflowStatus&          aStatus)
 {
   DO_GLOBAL_REFLOW_COUNT("nsInlineFrame");
   DISPLAY_REFLOW(aPresContext, this, aReflowState, aMetrics, aStatus);
   if (nullptr == aReflowState.mLineLayout) {
     return NS_ERROR_INVALID_ARG;
   }
+  if (IsFrameTreeTooDeep(aReflowState, aMetrics, aStatus)) {
+    return NS_OK;
+  }
 
   bool    lazilySetParentPointer = false;
 
   nsIFrame* lineContainer = aReflowState.mLineLayout->GetLineContainerFrame();
 
    // Check for an overflow list with our prev-in-flow
   nsInlineFrame* prevInFlow = (nsInlineFrame*)GetPrevInFlow();
   if (nullptr != prevInFlow) {
@@ -360,28 +363,38 @@ nsInlineFrame::Reflow(nsPresContext*    
     NS_ASSERTION(!overflowFrames || overflowFrames->IsEmpty(),
                  "overflow list is not empty for initial reflow");
   }
 #endif
   if (!(GetStateBits() & NS_FRAME_FIRST_REFLOW)) {
     nsAutoPtr<nsFrameList> overflowFrames(StealOverflowFrames());
     if (overflowFrames) {
       NS_ASSERTION(mFrames.NotEmpty(), "overflow list w/o frames");
-
-      // Because we lazily set the parent pointer of child frames we get from
-      // our prev-in-flow's overflow list, it's possible that we have not set
-      // the parent pointer for these frames.
-      mFrames.AppendFrames(this, *overflowFrames);
+      if (!lazilySetParentPointer) {
+        // The frames on our own overflowlist may have been pushed by a
+        // previous lazilySetParentPointer Reflow so we need to ensure
+        // the correct parent pointer now since we're not setting it
+        // lazily in this Reflow.
+        nsIFrame* firstChild = overflowFrames->FirstChild();
+        if (lineContainer && lineContainer->GetPrevContinuation()) {
+          ReparentFloatsForInlineChild(lineContainer, firstChild, true);
+        }
+        const bool inFirstLine = aReflowState.mLineLayout->GetInFirstLine();
+        nsFrameManager* fm = PresContext()->FrameManager();
+        for (nsIFrame* f = firstChild; f; f = f->GetNextSibling()) {
+          f->SetParent(this);
+          if (inFirstLine) {
+            fm->ReparentStyleContext(f);
+          }
+        }
+      }
+      mFrames.AppendFrames(nullptr, *overflowFrames);
     }
   }
 
-  if (IsFrameTreeTooDeep(aReflowState, aMetrics, aStatus)) {
-    return NS_OK;
-  }
-
   // Set our own reflow state (additional state above and beyond
   // aReflowState)
   InlineReflowState irs;
   irs.mPrevFrame = nullptr;
   irs.mLineContainer = lineContainer;
   irs.mLineLayout = aReflowState.mLineLayout;
   irs.mNextInFlow = (nsInlineFrame*) GetNextInFlow();
   irs.mSetParentPointer = lazilySetParentPointer;
@@ -465,52 +478,51 @@ nsInlineFrame::ReflowFrames(nsPresContex
   bool done = false;
   while (nullptr != frame) {
     bool reflowingFirstLetter = lineLayout->GetFirstLetterStyleOK();
 
     // Check if we should lazily set the child frame's parent pointer
     if (irs.mSetParentPointer) {
       bool havePrevBlock =
         irs.mLineContainer && irs.mLineContainer->GetPrevContinuation();
-      // If our block is the first in flow, then any floats under the pulled
-      // frame must already belong to our block.
-      if (havePrevBlock) {
-        // This has to happen before we update frame's parent; we need to
-        // know frame's ancestry under its old block.
-        // The blockChildren.ContainsFrame check performed by
-        // ReparentFloatsForInlineChild here may be slow, but we can't
-        // easily avoid it because we don't know where 'frame' originally
-        // came from. If we really really have to optimize this we could
-        // cache whether frame->GetParent() is under its containing blocks
-        // overflowList or not.
-        ReparentFloatsForInlineChild(irs.mLineContainer, frame, false);
-      }
-      frame->SetParent(this);
-      if (inFirstLine) {
-        frameManager->ReparentStyleContext(frame);
-      }
-      // We also need to check if frame has a next-in-flow. If it does, then set
-      // its parent frame pointer, too. Otherwise, if we reflow frame and it's
-      // complete we'll fail when deleting its next-in-flow which is no longer
-      // needed. This scenario doesn't happen often, but it can happen
-      nsIFrame* nextInFlow = frame->GetNextInFlow();
-      for ( ; nextInFlow; nextInFlow = nextInFlow->GetNextInFlow()) {
-        // Since we only do lazy setting of parent pointers for the frame's
-        // initial reflow, this frame can't have a next-in-flow. That means
-        // the continuing child frame must be in our child list as well. If
-        // not, then something is wrong
-        NS_ASSERTION(mFrames.ContainsFrame(nextInFlow), "unexpected flow");
+      nsIFrame* child = frame;
+      do {
+        // If our block is the first in flow, then any floats under the pulled
+        // frame must already belong to our block.
         if (havePrevBlock) {
-          ReparentFloatsForInlineChild(irs.mLineContainer, nextInFlow, false);
+          // This has to happen before we update frame's parent; we need to
+          // know frame's ancestry under its old block.
+          // The blockChildren.ContainsFrame check performed by
+          // ReparentFloatsForInlineChild here may be slow, but we can't
+          // easily avoid it because we don't know where 'frame' originally
+          // came from. If we really really have to optimize this we could
+          // cache whether frame->GetParent() is under its containing blocks
+          // overflowList or not.
+          ReparentFloatsForInlineChild(irs.mLineContainer, child, false);
         }
-        nextInFlow->SetParent(this);
+        child->SetParent(this);
         if (inFirstLine) {
-          frameManager->ReparentStyleContext(nextInFlow);
+          frameManager->ReparentStyleContext(child);
         }
-      }
+        // We also need to do the same for |frame|'s next-in-flows that are in
+        // the sibling list. Otherwise, if we reflow |frame| and it's complete
+        // we'll crash when trying to delete its next-in-flow.
+        // This scenario doesn't happen often, but it can happen.
+        nsIFrame* nextSibling = child->GetNextSibling();
+        child = child->GetNextInFlow();
+        if (NS_UNLIKELY(child)) {
+          while (child != nextSibling && nextSibling) {
+            nextSibling = nextSibling->GetNextSibling();
+          }
+          if (!nextSibling) {
+            child = nullptr;
+          }
+        }
+        MOZ_ASSERT(!child || mFrames.ContainsFrame(child));
+      } while (child);
 
       // Fix the parent pointer for ::first-letter child frame next-in-flows,
       // so nsFirstLetterFrame::Reflow can destroy them safely (bug 401042).
       nsIFrame* realFrame = nsPlaceholderFrame::GetRealFrameFor(frame);
       if (realFrame->GetType() == nsGkAtoms::letterFrame) {
         nsIFrame* child = realFrame->GetFirstPrincipalChild();
         if (child) {
           NS_ASSERTION(child->GetType() == nsGkAtoms::textFrame,
@@ -535,68 +547,71 @@ nsInlineFrame::ReflowFrames(nsPresContex
               }
 #endif
               break;
             }
           }
         }
       }
     }
-    rv = ReflowInlineFrame(aPresContext, aReflowState, irs, frame, aStatus);
-    if (NS_FAILED(rv)) {
-      done = true;
-      break;
+    MOZ_ASSERT(frame->GetParent() == this);
+
+    if (!done) {
+      rv = ReflowInlineFrame(aPresContext, aReflowState, irs, frame, aStatus);
+      done = NS_FAILED(rv) ||
+             NS_INLINE_IS_BREAK(aStatus) || 
+             (!reflowingFirstLetter && NS_FRAME_IS_NOT_COMPLETE(aStatus));
+      if (done) {
+        if (!irs.mSetParentPointer) {
+          break;
+        }
+        // Keep reparenting the remaining siblings, but don't reflow them.
+        nsFrameList* pushedFrames = GetOverflowFrames();
+        if (pushedFrames && pushedFrames->FirstChild() == frame) {
+          // Don't bother if |frame| was pushed to our overflow list.
+          break;
+        }
+      } else {
+        irs.mPrevFrame = frame;
+      }
     }
-    if (NS_INLINE_IS_BREAK(aStatus) || 
-        (!reflowingFirstLetter && NS_FRAME_IS_NOT_COMPLETE(aStatus))) {
-      done = true;
-      break;
-    }
-    irs.mPrevFrame = frame;
     frame = frame->GetNextSibling();
   }
 
   // Attempt to pull frames from our next-in-flow until we can't
-  if (!done && (nullptr != GetNextInFlow())) {
-    while (!done) {
+  if (!done && GetNextInFlow()) {
+    while (true) {
       bool reflowingFirstLetter = lineLayout->GetFirstLetterStyleOK();
       bool isComplete;
       if (!frame) { // Could be non-null if we pulled a first-letter frame and
                     // it created a continuation, since we don't push those.
         frame = PullOneFrame(aPresContext, irs, &isComplete);
       }
 #ifdef NOISY_PUSHING
       printf("%p pulled up %p\n", this, frame);
 #endif
       if (nullptr == frame) {
         if (!isComplete) {
           aStatus = NS_FRAME_NOT_COMPLETE;
         }
         break;
       }
       rv = ReflowInlineFrame(aPresContext, aReflowState, irs, frame, aStatus);
-      if (NS_FAILED(rv)) {
-        done = true;
-        break;
-      }
-      if (NS_INLINE_IS_BREAK(aStatus) || 
+      if (NS_FAILED(rv) ||
+          NS_INLINE_IS_BREAK(aStatus) || 
           (!reflowingFirstLetter && NS_FRAME_IS_NOT_COMPLETE(aStatus))) {
-        done = true;
         break;
       }
       irs.mPrevFrame = frame;
       frame = frame->GetNextSibling();
     }
   }
-#ifdef DEBUG
-  if (NS_FRAME_IS_COMPLETE(aStatus)) {
-    // We can't be complete AND have overflow frames!
-    NS_ASSERTION(!GetOverflowFrames(), "whoops");
-  }
-#endif
+
+  NS_ASSERTION(!NS_FRAME_IS_COMPLETE(aStatus) || !GetOverflowFrames(),
+               "We can't be complete AND have overflow frames!");
 
   // If after reflowing our children they take up no area then make
   // sure that we don't either.
   //
   // Note: CSS demands that empty inline elements still affect the
   // line-height calculations. However, continuations of an inline
   // that are empty we force to empty so that things like collapsed
   // whitespace in an inline element don't affect the line-height.
@@ -691,32 +706,16 @@ nsInlineFrame::ReflowInlineFrame(nsPresC
       aStatus = NS_FRAME_NOT_COMPLETE |
         NS_INLINE_BREAK | NS_INLINE_BREAK_AFTER |
         (aStatus & NS_INLINE_BREAK_TYPE_MASK);
       PushFrames(aPresContext, aFrame, irs.mPrevFrame, irs);
     }
     else {
       // Preserve reflow status when breaking-before our first child
       // and propagate it upward without modification.
-      // Note: if we're lazily setting the frame pointer for our child 
-      // frames, then we need to set it now. Don't return and leave the
-      // remaining child frames in our child list with the wrong parent
-      // frame pointer...
-      if (irs.mSetParentPointer) {
-        if (irs.mLineContainer && irs.mLineContainer->GetPrevContinuation()) {
-          ReparentFloatsForInlineChild(irs.mLineContainer, aFrame->GetNextSibling(),
-                                       true);
-        }
-        for (nsIFrame* f = aFrame->GetNextSibling(); f; f = f->GetNextSibling()) {
-          f->SetParent(this);
-          if (lineLayout->GetInFirstLine()) {
-            aPresContext->FrameManager()->ReparentStyleContext(f);
-          }
-        }
-      }
     }
     return NS_OK;
   }
 
   // Create a next-in-flow if needed.
   if (!NS_FRAME_IS_FULLY_COMPLETE(aStatus)) {
     nsIFrame* newFrame;
     rv = CreateNextInFlow(aPresContext, aFrame, newFrame);
@@ -761,47 +760,48 @@ nsInlineFrame::PullOneFrame(nsPresContex
                             bool* aIsComplete)
 {
   bool isComplete = true;
 
   nsIFrame* frame = nullptr;
   nsInlineFrame* nextInFlow = irs.mNextInFlow;
   while (nullptr != nextInFlow) {
     frame = nextInFlow->mFrames.FirstChild();
-
     if (!frame) {
-      // If the principal childlist has no frames, then try moving the overflow
-      // frames to it.
-      nsAutoPtr<nsFrameList> overflowFrames(nextInFlow->StealOverflowFrames());
+      // The nextInFlow's principal list has no frames, try its overflow list.
+      nsFrameList* overflowFrames = nextInFlow->GetOverflowFrames();
       if (overflowFrames) {
-        nextInFlow->mFrames.SetFrames(*overflowFrames);
-        frame = nextInFlow->mFrames.FirstChild();
+        frame = overflowFrames->FirstChild();
+        if (!frame->GetNextSibling()) {
+          // We're stealing the only frame - delete the overflow list.
+          delete nextInFlow->StealOverflowFrames();
+        } else {
+          // We leave the remaining frames on the overflow list (rather than
+          // putting them on nextInFlow's principal list) so we don't have to
+          // set up the parent for them.
+          overflowFrames->RemoveFirstChild();
+        }
+        // ReparentFloatsForInlineChild needs it to be on a child list -
+        // we remove it again below.
+        nextInFlow->mFrames.SetFrames(frame);
       }
     }
 
     if (nullptr != frame) {
       // If our block has no next continuation, then any floats belonging to
       // the pulled frame must belong to our block already. This check ensures
       // we do no extra work in the common non-vertical-breaking case.
       if (irs.mLineContainer && irs.mLineContainer->GetNextContinuation()) {
         // The blockChildren.ContainsFrame check performed by
         // ReparentFloatsForInlineChild will be fast because frame's ancestor
         // will be the first child of its containing block.
         ReparentFloatsForInlineChild(irs.mLineContainer, frame, false);
       }
       nextInFlow->mFrames.RemoveFirstChild();
-
-      // If we removed the last frame from the principal child list then move
-      // any overflow frames to it.
-      if (!nextInFlow->mFrames.FirstChild()) {
-        nsAutoPtr<nsFrameList> overflowFrames(nextInFlow->StealOverflowFrames());
-        if (overflowFrames) {
-          nextInFlow->mFrames.SetFrames(*overflowFrames);
-        }
-      }
+      // nsFirstLineFrame::PullOneFrame calls ReparentStyleContext.
 
       mFrames.InsertFrame(this, irs.mPrevFrame, frame);
       isComplete = false;
       if (irs.mLineLayout) {
         irs.mLineLayout->SetDirtyNextLine();
       }
       nsContainerFrame::ReparentFrameView(aPresContext, frame, nextInFlow, this);
       break;
--- a/layout/generic/nsTextFrameThebes.cpp
+++ b/layout/generic/nsTextFrameThebes.cpp
@@ -1549,25 +1549,27 @@ BuildTextRunsScanner::ContinueTextRunAcr
     // breaks text into different frames even though the text has the same
     // direction. We can't allow these two frames to share the same textrun
     // because that would violate our invariant that two flows in the same
     // textrun have different content elements.
     return false;
   }
 
   nsStyleContext* sc2 = aFrame2->GetStyleContext();
+  const nsStyleText* textStyle2 = sc2->GetStyleText();
   if (sc1 == sc2)
     return true;
 
   const nsStyleFont* fontStyle1 = sc1->GetStyleFont();
   const nsStyleFont* fontStyle2 = sc2->GetStyleFont();
   nscoord letterSpacing1 = LetterSpacing(aFrame1);
   nscoord letterSpacing2 = LetterSpacing(aFrame2);
   return fontStyle1->mFont.BaseEquals(fontStyle2->mFont) &&
     sc1->GetStyleFont()->mLanguage == sc2->GetStyleFont()->mLanguage &&
+    textStyle1->mTextTransform == textStyle2->mTextTransform &&
     nsLayoutUtils::GetTextRunFlagsForStyle(sc1, fontStyle1, letterSpacing1) ==
       nsLayoutUtils::GetTextRunFlagsForStyle(sc2, fontStyle2, letterSpacing2);
 }
 
 void BuildTextRunsScanner::ScanFrame(nsIFrame* aFrame)
 {
   // First check if we can extend the current mapped frame block. This is common.
   if (mMappedFlows.Length() > 0) {
--- a/layout/mathml/nsMathMLmtableFrame.cpp
+++ b/layout/mathml/nsMathMLmtableFrame.cpp
@@ -497,17 +497,17 @@ nsMathMLmtableOuterFrame::AttributeChang
         }
       }
     }
   }
 
   // Explicitly request a re-resolve and reflow in our subtree to pick up any changes
   presContext->PresShell()->FrameConstructor()->
     PostRestyleEvent(mContent->AsElement(), eRestyle_Subtree,
-                     nsChangeHint_ReflowFrame);
+                     nsChangeHint_AllReflowHints);
 
   return NS_OK;
 }
 
 nsIFrame*
 nsMathMLmtableOuterFrame::GetRowFrameAt(nsPresContext* aPresContext,
                                         int32_t         aRowIndex)
 {
@@ -679,17 +679,17 @@ void
 nsMathMLmtableFrame::RestyleTable()
 {
   // re-sync MathML specific style data that may have changed
   MapAllAttributesIntoCSS(this);
 
   // Explicitly request a re-resolve and reflow in our subtree to pick up any changes
   PresContext()->PresShell()->FrameConstructor()->
     PostRestyleEvent(mContent->AsElement(), eRestyle_Subtree,
-                     nsChangeHint_ReflowFrame);
+                     nsChangeHint_AllReflowHints);
 }
 
 // --------
 // implementation of nsMathMLmtrFrame
 
 nsIFrame*
 NS_NewMathMLmtrFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
 {
@@ -740,17 +740,17 @@ nsMathMLmtrFrame::AttributeChanged(int32
                   false);
       MapColAttributesIntoCSS(tableFrame, this, cellFrame);
     }
   }
 
   // Explicitly request a re-resolve and reflow in our subtree to pick up any changes
   presContext->PresShell()->FrameConstructor()->
     PostRestyleEvent(mContent->AsElement(), eRestyle_Subtree,
-                     nsChangeHint_ReflowFrame);
+                     nsChangeHint_AllReflowHints);
 
   return NS_OK;
 }
 
 // --------
 // implementation of nsMathMLmtdFrame
 
 nsIFrame*
new file mode 100644
--- /dev/null
+++ b/layout/reftests/table-width/colspan-distribute-to-empty-1-ref.html
@@ -0,0 +1,14 @@
+<!DOCTYPE HTML>
+<title>Distributing widths from spanning cells to empty columns</title>
+<table cellpadding="0" cellspacing="0" width="75">
+  <tr>
+    <td width="25" bgcolor="yellow" >&nbsp;</td>
+    <td width="25" bgcolor="aqua"   >&nbsp;</td>
+    <td width="25" bgcolor="aqua"   >&nbsp;</td>
+  </tr>
+  <tr>
+    <td width="25" bgcolor="fuchsia">&nbsp;</td>
+    <td width="25" bgcolor="fuchsia">&nbsp;</td>
+    <td width="25" bgcolor="yellow" >&nbsp;</td>
+  </tr>
+</table>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/table-width/colspan-distribute-to-empty-1a.html
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML>
+<title>Distributing widths from spanning cells to empty columns</title>
+<table cellpadding="0" cellspacing="0">
+  <tr>
+    <td width="25"             bgcolor="yellow" >&nbsp;</td>
+    <td width="50" colspan="2" bgcolor="aqua"   >&nbsp;</td>
+  </tr>
+  <tr>
+    <td width="50" colspan="2" bgcolor="fuchsia">&nbsp;</td>
+    <td width="25"             bgcolor="yellow" >&nbsp;</td>
+  </tr>
+</table>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/table-width/colspan-distribute-to-empty-1b.html
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML>
+<title>Distributing widths from spanning cells to empty columns</title>
+<table cellpadding="0" cellspacing="0" width="75">
+  <tr>
+    <td width="25"             bgcolor="yellow" >&nbsp;</td>
+    <td width="50" colspan="2" bgcolor="aqua"   >&nbsp;</td>
+  </tr>
+  <tr>
+    <td width="50" colspan="2" bgcolor="fuchsia">&nbsp;</td>
+    <td width="25"             bgcolor="yellow" >&nbsp;</td>
+  </tr>
+</table>
--- a/layout/reftests/table-width/reftest.list
+++ b/layout/reftests/table-width/reftest.list
@@ -55,8 +55,10 @@ fails == default-box-sizing-collapse-qui
 == spanning-cell-sort-2-small-fixed.html spanning-cell-sort-2-fixed-ref.html
 == spanning-cell-sort-2-large-fixed.html spanning-cell-sort-2-fixed-ref.html
 == colgroup-vs-column-1.html colgroup-vs-column-1-ref.html
 == colgroup-vs-column-2.html colgroup-vs-column-2-ref.html
 == colgroup-vs-column-3.html colgroup-vs-column-3-ref.html
 == colgroup-vs-column-4.html colgroup-vs-column-4-ref.html
 == dynamic-fixed-layout-1.html dynamic-fixed-layout-1-ref.html
 == cell-pref-width-border-box.html cell-pref-width-border-box-ref.html
+== colspan-distribute-to-empty-1a.html colspan-distribute-to-empty-1-ref.html
+== colspan-distribute-to-empty-1b.html colspan-distribute-to-empty-1-ref.html
new file mode 100644
--- /dev/null
+++ b/layout/reftests/text-transform/capitalize-7-ref.html
@@ -0,0 +1,6 @@
+<!DOCTYPE html>
+<html>
+<body>
+<p>Blah Blah</p>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/text-transform/capitalize-7.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html>
+<style>
+p:first-letter { text-transform: uppercase; }
+p { text-transform: capitalize }
+</style>
+<body>
+<p>blah blah</p>
+</body>
+</html>
--- a/layout/reftests/text-transform/reftest.list
+++ b/layout/reftests/text-transform/reftest.list
@@ -1,14 +1,15 @@
 == capitalize-1.html capitalize-ref.html
 == capitalize-2.html capitalize-ref.html
 == capitalize-3.html capitalize-3-ref.html
 == capitalize-4.html capitalize-4-ref.html
 == capitalize-5.html capitalize-5-ref.html
 == capitalize-6.html capitalize-6-ref.html
+== capitalize-7.html capitalize-7-ref.html
 == lowercase-1.html lowercase-ref.html
 == lowercase-sigma-1.html lowercase-sigma-1-ref.html
 == small-caps-1.html small-caps-1-ref.html
 == uppercase-1.html uppercase-ref.html
 == uppercase-szlig-1.html uppercase-szlig-ref.html
 # these use DejaVu Sans via @font-face for consistency of results
 HTTP(..) == all-upper.html all-upper-ref.html
 HTTP(..) == all-lower.html all-lower-ref.html
--- a/layout/style/nsStyleStruct.cpp
+++ b/layout/style/nsStyleStruct.cpp
@@ -493,17 +493,17 @@ nsChangeHint nsStyleBorder::CalcDifferen
   // Note that differences in mBorder don't affect rendering (which should only
   // use mComputedBorder), so don't need to be tested for here.
   // XXXbz we should be able to return a more specific change hint for
   // at least GetComputedBorder() differences...
   if (mTwipsPerPixel != aOther.mTwipsPerPixel ||
       GetComputedBorder() != aOther.GetComputedBorder() ||
       mFloatEdge != aOther.mFloatEdge ||
       mBorderImageOutset != aOther.mBorderImageOutset ||
-      (shadowDifference & nsChangeHint_ReflowFrame))
+      (shadowDifference & nsChangeHint_NeedReflow))
     return NS_STYLE_HINT_REFLOW;
 
   NS_FOR_CSS_SIDES(ix) {
     // See the explanation in nsChangeHint.h of
     // nsChangeHint_BorderStyleNoneChange .
     // Furthermore, even though we know *this* side is 0 width, just
     // assume a visual hint for some other change rather than bother
     // tracking this result through the rest of the function.
@@ -635,17 +635,18 @@ nsChangeHint nsStyleOutline::CalcDiffere
   bool outlineWasVisible =
     mCachedOutlineWidth > 0 && mOutlineStyle != NS_STYLE_BORDER_STYLE_NONE;
   bool outlineIsVisible = 
     aOther.mCachedOutlineWidth > 0 && aOther.mOutlineStyle != NS_STYLE_BORDER_STYLE_NONE;
   if (outlineWasVisible != outlineIsVisible ||
       (outlineIsVisible && (mOutlineOffset != aOther.mOutlineOffset ||
                             mOutlineWidth != aOther.mOutlineWidth ||
                             mTwipsPerPixel != aOther.mTwipsPerPixel))) {
-    return NS_CombineHint(nsChangeHint_ReflowFrame, nsChangeHint_RepaintFrame);
+    return NS_CombineHint(nsChangeHint_AllReflowHints,
+                          nsChangeHint_RepaintFrame);
   }
   if ((mOutlineStyle != aOther.mOutlineStyle) ||
       (mOutlineColor != aOther.mOutlineColor) ||
       (mOutlineRadius != aOther.mOutlineRadius)) {
     return nsChangeHint_RepaintFrame;
   }
   return NS_STYLE_HINT_NONE;
 }
@@ -888,17 +889,17 @@ static bool PaintURIChanged(const nsStyl
 
 nsChangeHint nsStyleSVG::CalcDifference(const nsStyleSVG& aOther) const
 {
   nsChangeHint hint = nsChangeHint(0);
 
   if (mTextRendering != aOther.mTextRendering) {
     NS_UpdateHint(hint, nsChangeHint_RepaintFrame);
     // May be needed for non-svg frames
-    NS_UpdateHint(hint, nsChangeHint_ReflowFrame);
+    NS_UpdateHint(hint, nsChangeHint_AllReflowHints);
   }
 
   if (!EqualURIs(mMarkerEnd, aOther.mMarkerEnd) ||
       !EqualURIs(mMarkerMid, aOther.mMarkerMid) ||
       !EqualURIs(mMarkerStart, aOther.mMarkerStart)) {
     NS_UpdateHint(hint, nsChangeHint_RepaintFrame);
     NS_UpdateHint(hint, nsChangeHint_UpdateEffects);
     return hint;
@@ -992,17 +993,17 @@ nsStyleSVGReset::nsStyleSVGReset(const n
 nsChangeHint nsStyleSVGReset::CalcDifference(const nsStyleSVGReset& aOther) const
 {
   nsChangeHint hint = nsChangeHint(0);
 
   if (!EqualURIs(mClipPath, aOther.mClipPath) ||
       !EqualURIs(mFilter, aOther.mFilter)     ||
       !EqualURIs(mMask, aOther.mMask)) {
     NS_UpdateHint(hint, nsChangeHint_UpdateEffects);
-    NS_UpdateHint(hint, nsChangeHint_ReflowFrame);
+    NS_UpdateHint(hint, nsChangeHint_AllReflowHints);
     NS_UpdateHint(hint, nsChangeHint_RepaintFrame);
   } else if (mDominantBaseline != aOther.mDominantBaseline) {
     NS_UpdateHint(hint, nsChangeHint_NeedReflow);
     NS_UpdateHint(hint, nsChangeHint_NeedDirtyReflow);
   } else if (mStopColor     != aOther.mStopColor     ||
              mFloodColor    != aOther.mFloodColor    ||
              mLightingColor != aOther.mLightingColor ||
              mStopOpacity   != aOther.mStopOpacity   ||
@@ -1108,40 +1109,40 @@ nsStylePosition::nsStylePosition(const n
 
 nsChangeHint nsStylePosition::CalcDifference(const nsStylePosition& aOther) const
 {
   nsChangeHint hint =
     (mZIndex == aOther.mZIndex) ? NS_STYLE_HINT_NONE : nsChangeHint_RepaintFrame;
 
   if (mBoxSizing != aOther.mBoxSizing) {
     // Can affect both widths and heights; just a bad scene.
-    return NS_CombineHint(hint, nsChangeHint_ReflowFrame);
+    return NS_CombineHint(hint, nsChangeHint_AllReflowHints);
   }
 
 #ifdef MOZ_FLEXBOX
   // Properties that apply to flex items:
   // NOTE: Changes to "order" on a flex item may trigger some repositioning.
   // If we're in a multi-line flex container, it also may affect our size
   // (and that of our container & siblings) by shuffling items between lines.
   if (mAlignSelf != aOther.mAlignSelf ||
       mFlexBasis != aOther.mFlexBasis ||
       mFlexGrow != aOther.mFlexGrow ||
       mFlexShrink != aOther.mFlexShrink ||
       mOrder != aOther.mOrder) {
-    return NS_CombineHint(hint, nsChangeHint_ReflowFrame);
+    return NS_CombineHint(hint, nsChangeHint_AllReflowHints);
   }
 
   // Properties that apply to flexbox containers:
 
   // flex-direction can swap a flexbox between vertical & horizontal.
   // align-items can change the sizing of a flexbox & the positioning
   // of its children.
   if (mAlignItems != aOther.mAlignItems ||
       mFlexDirection != aOther.mFlexDirection) {
-    return NS_CombineHint(hint, nsChangeHint_ReflowFrame);
+    return NS_CombineHint(hint, nsChangeHint_AllReflowHints);
   }
 
   // Changing justify-content on a flexbox might affect the positioning of its
   // children, but it won't affect any sizing.
   if (mJustifyContent != aOther.mJustifyContent) {
     NS_UpdateHint(hint, nsChangeHint_NeedReflow);
   }
 #endif // MOZ_FLEXBOX
@@ -1150,27 +1151,27 @@ nsChangeHint nsStylePosition::CalcDiffer
       mMinHeight != aOther.mMinHeight ||
       mMaxHeight != aOther.mMaxHeight) {
     // Height changes can affect descendant intrinsic sizes due to replaced
     // elements with percentage heights in descendants which also have
     // percentage heights.  And due to our not-so-great computation of mVResize
     // in nsHTMLReflowState, they do need to force reflow of the whole subtree.
     // XXXbz due to XUL caching heights as well, height changes also need to
     // clear ancestor intrinsics!
-    return NS_CombineHint(hint, nsChangeHint_ReflowFrame);
+    return NS_CombineHint(hint, nsChangeHint_AllReflowHints);
   }
 
   if (mWidth != aOther.mWidth ||
       mMinWidth != aOther.mMinWidth ||
       mMaxWidth != aOther.mMaxWidth) {
     // None of our width differences can affect descendant intrinsic
     // sizes and none of them need to force children to reflow.
     return
       NS_CombineHint(hint,
-                     NS_SubtractHint(nsChangeHint_ReflowFrame,
+                     NS_SubtractHint(nsChangeHint_AllReflowHints,
                                      NS_CombineHint(nsChangeHint_ClearDescendantIntrinsics,
                                                     nsChangeHint_NeedDirtyReflow)));
   }
 
   // If width and height have not changed, but any of the offsets have changed,
   // then return the respective hints so that we would hopefully be able to
   // avoid reflowing.
   // Note that it is possible that we'll need to reflow when processing
@@ -2183,30 +2184,31 @@ nsChangeHint nsStyleDisplay::CalcDiffere
       || mOverflowX != aOther.mOverflowX
       || mOverflowY != aOther.mOverflowY
       || mResize != aOther.mResize)
     NS_UpdateHint(hint, nsChangeHint_ReconstructFrame);
 
   if (mFloats != aOther.mFloats) {
     // Changing which side we float on doesn't affect descendants directly
     NS_UpdateHint(hint,
-       NS_SubtractHint(nsChangeHint_ReflowFrame,
+       NS_SubtractHint(nsChangeHint_AllReflowHints,
                        NS_CombineHint(nsChangeHint_ClearDescendantIntrinsics,
                                       nsChangeHint_NeedDirtyReflow)));
   }
 
   // XXX the following is conservative, for now: changing float breaking shouldn't
   // necessarily require a repaint, reflow should suffice.
   if (mBreakType != aOther.mBreakType
       || mBreakBefore != aOther.mBreakBefore
       || mBreakAfter != aOther.mBreakAfter
       || mAppearance != aOther.mAppearance
       || mOrient != aOther.mOrient
       || mClipFlags != aOther.mClipFlags || !mClip.IsEqualInterior(aOther.mClip))
-    NS_UpdateHint(hint, NS_CombineHint(nsChangeHint_ReflowFrame, nsChangeHint_RepaintFrame));
+    NS_UpdateHint(hint, NS_CombineHint(nsChangeHint_AllReflowHints,
+                                       nsChangeHint_RepaintFrame));
 
   if (mOpacity != aOther.mOpacity) {
     NS_UpdateHint(hint, nsChangeHint_UpdateOpacityLayer);
   }
 
   /* If we've added or removed the transform property, we need to reconstruct the frame to add
    * or remove the view object, and also to handle abs-pos and fixed-pos containers.
    */
--- a/layout/style/nsStyleStruct.h
+++ b/layout/style/nsStyleStruct.h
@@ -950,17 +950,18 @@ struct nsStyleOutline {
   void Destroy(nsPresContext* aContext) {
     this->~nsStyleOutline();
     aContext->FreeToShell(sizeof(nsStyleOutline), this);
   }
 
   void RecalcData(nsPresContext* aContext);
   nsChangeHint CalcDifference(const nsStyleOutline& aOther) const;
   static nsChangeHint MaxDifference() {
-    return NS_CombineHint(nsChangeHint_ReflowFrame, nsChangeHint_RepaintFrame);
+    return NS_CombineHint(nsChangeHint_AllReflowHints,
+                          nsChangeHint_RepaintFrame);
   }
 
   nsStyleCorners  mOutlineRadius; // [reset] coord, percent, calc
 
   // Note that this is a specified value.  You can get the actual values
   // with GetOutlineWidth.  You cannot get the computed value directly.
   nsStyleCoord  mOutlineWidth;    // [reset] coord, enum (see nsStyleConsts.h)
   nscoord       mOutlineOffset;   // [reset]
@@ -2198,17 +2199,17 @@ struct nsStyleSVG {
   void Destroy(nsPresContext* aContext) {
     this->~nsStyleSVG();
     aContext->FreeToShell(sizeof(nsStyleSVG), this);
   }
 
   nsChangeHint CalcDifference(const nsStyleSVG& aOther) const;
   static nsChangeHint MaxDifference() {
     return NS_CombineHint(NS_CombineHint(nsChangeHint_UpdateEffects,
-                                         nsChangeHint_ReflowFrame),
+                                         nsChangeHint_AllReflowHints),
                                          nsChangeHint_RepaintFrame);
   }
 
   nsStyleSVGPaint  mFill;             // [inherited]
   nsStyleSVGPaint  mStroke;           // [inherited]
   nsCOMPtr<nsIURI> mMarkerEnd;        // [inherited]
   nsCOMPtr<nsIURI> mMarkerMid;        // [inherited]
   nsCOMPtr<nsIURI> mMarkerStart;      // [inherited]
@@ -2255,17 +2256,17 @@ struct nsStyleSVGReset {
   void Destroy(nsPresContext* aContext) {
     this->~nsStyleSVGReset();
     aContext->FreeToShell(sizeof(nsStyleSVGReset), this);
   }
 
   nsChangeHint CalcDifference(const nsStyleSVGReset& aOther) const;
   static nsChangeHint MaxDifference() {
     return NS_CombineHint(NS_CombineHint(nsChangeHint_UpdateEffects,
-                                         nsChangeHint_ReflowFrame),
+                                         nsChangeHint_AllReflowHints),
                                          nsChangeHint_RepaintFrame);
   }
 
   nsCOMPtr<nsIURI> mClipPath;         // [reset]
   nsCOMPtr<nsIURI> mFilter;           // [reset]
   nsCOMPtr<nsIURI> mMask;             // [reset]
   nscolor          mStopColor;        // [reset]
   nscolor          mFloodColor;       // [reset]
--- a/layout/svg/base/src/nsSVGEffects.cpp
+++ b/layout/svg/base/src/nsSVGEffects.cpp
@@ -272,17 +272,17 @@ nsSVGMarkerProperty::DoUpdate()
 
   // Repaint asynchronously in case the filter frame is being torn down
   nsChangeHint changeHint =
     nsChangeHint(nsChangeHint_RepaintFrame | nsChangeHint_UpdateEffects);
   
   // Don't need to request ReflowFrame if we're being reflowed.
   if (!(mFrame->GetStateBits() & NS_FRAME_IN_REFLOW)) {
     // XXXjwatt: We need to unify SVG into standard reflow so we can just use
-    // nsChangeHint_ReflowFrame here.
+    // nsChangeHint_NeedReflow | nsChangeHint_NeedDirtyReflow here.
     nsSVGUtils::InvalidateAndScheduleReflowSVG(mFrame);
   }
   mFramePresShell->FrameConstructor()->PostRestyleEvent(
     mFrame->GetContent()->AsElement(), nsRestyleHint(0), changeHint);
 }
 
 void
 nsSVGTextPathProperty::DoUpdate()
--- a/layout/tables/BasicTableLayoutStrategy.cpp
+++ b/layout/tables/BasicTableLayoutStrategy.cpp
@@ -695,20 +695,20 @@ BasicTableLayoutStrategy::DistributeWidt
      *
      * If |aWidth| is *larger* than what we would assign in (4), then we
      * expand the columns:
      *
      *   a. if any columns without a specified coordinate width or
      *   percent width have nonzero pref width, in proportion to pref
      *   width [total_flex_pref]
      *
-     *   b. (NOTE: this case is for BTLS_FINAL_WIDTH only) otherwise, if
-     *   any columns without a specified coordinate width or percent
-     *   width, but with cells originating in them have zero pref width,
-     *   equally between these [numNonSpecZeroWidthCols]
+     *   b. otherwise, if any columns without a specified coordinate
+     *   width or percent width, but with cells originating in them,
+     *   have zero pref width, equally between these
+     *   [numNonSpecZeroWidthCols]
      *
      *   c. otherwise, if any columns without percent width have nonzero
      *   pref width, in proportion to pref width [total_fixed_pref]
      *
      *   d. otherwise, if any columns have nonzero percentage widths, in
      *   proportion to the percentage widths [total_pct]
      *
      *   e. otherwise, equally.
@@ -756,18 +756,17 @@ BasicTableLayoutStrategy::DistributeWidt
                 // we'll add on the rest of guess_min_spec outside the
                 // loop
                 nscoord delta = NSCoordSaturatingSubtract(pref_width, 
                                                           min_width, 0);
                 guess_min_spec = NSCoordSaturatingAdd(guess_min_spec, delta);
                 total_fixed_pref = NSCoordSaturatingAdd(total_fixed_pref, 
                                                         pref_width);
             } else if (pref_width == 0) {
-                if (aWidthType == BTLS_FINAL_WIDTH &&
-                    cellMap->GetNumCellsOriginatingInCol(col) > 0) {
+                if (cellMap->GetNumCellsOriginatingInCol(col) > 0) {
                     ++numNonSpecZeroWidthCols;
                 }
             } else {
                 total_flex_pref = NSCoordSaturatingAdd(total_flex_pref,
                                                        pref_width);
             }
         }
     }
@@ -818,19 +817,16 @@ BasicTableLayoutStrategy::DistributeWidt
                                                 nscoord_MAX);
         }
     } else {
         space = NSCoordSaturatingSubtract(aWidth, guess_pref, nscoord_MAX);
         if (total_flex_pref > 0) {
             l2t = FLEX_FLEX_LARGE;
             basis.c = total_flex_pref;
         } else if (numNonSpecZeroWidthCols > 0) {
-            NS_ASSERTION(aWidthType == BTLS_FINAL_WIDTH,
-                         "numNonSpecZeroWidthCols should only "
-                         "be set when we're setting final width.");
             l2t = FLEX_FLEX_LARGE_ZERO;
             basis.c = numNonSpecZeroWidthCols;
         } else if (total_fixed_pref > 0) {
             l2t = FLEX_FIXED_LARGE;
             basis.c = total_fixed_pref;
         } else if (total_pct > 0.0f) {
             l2t = FLEX_PCT_LARGE;
             basis.f = total_pct;
@@ -950,19 +946,16 @@ BasicTableLayoutStrategy::DistributeWidt
                             float c = float(space) / float(basis.c);
                             basis.c -= col_width;
                             col_width += NSToCoordRound(float(col_width) * c);
                         }
                     }
                 }
                 break;
             case FLEX_FLEX_LARGE_ZERO:
-                NS_ASSERTION(aWidthType == BTLS_FINAL_WIDTH,
-                             "FLEX_FLEX_LARGE_ZERO only should be hit "
-                             "when we're setting final width.");
                 if (pct == 0.0f &&
                     !colFrame->GetHasSpecifiedCoord() &&
                     cellMap->GetNumCellsOriginatingInCol(col) > 0) {
 
                     NS_ASSERTION(col_width == 0 &&
                                  colFrame->GetPrefCoord() == 0,
                                  "Since we're in FLEX_FLEX_LARGE_ZERO case, "
                                  "all auto-width cols should have zero pref "
--- a/layout/tables/SpanningCellSorter.h
+++ b/layout/tables/SpanningCellSorter.h
@@ -3,16 +3,17 @@
 /* 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/. */
 
 /*
  * Code to sort cells by their colspan, used by BasicTableLayoutStrategy.
  */
 
+#include "prtypes.h"
 #include "pldhash.h"
 #include "nsDebug.h"
 #include "StackArena.h"
 
 class nsIPresShell;
 
 /**
  * The SpanningCellSorter is responsible for accumulating lists of cells
--- a/layout/tables/nsTableFrame.cpp
+++ b/layout/tables/nsTableFrame.cpp
@@ -4610,17 +4610,17 @@ nsTableFrame::BCRecalcNeeded(nsStyleCont
   const nsStyleBorder* oldStyleData = aOldStyleContext->PeekStyleBorder();
   if (!oldStyleData)
     return false;
 
   const nsStyleBorder* newStyleData = aNewStyleContext->GetStyleBorder();
   nsChangeHint change = newStyleData->CalcDifference(*oldStyleData);
   if (!change)
     return false;
-  if (change & nsChangeHint_ReflowFrame)
+  if (change & nsChangeHint_NeedReflow)
     return true; // the caller only needs to mark the bc damage area
   if (change & nsChangeHint_RepaintFrame) {
     // we need to recompute the borders and the caller needs to mark
     // the bc damage area
     // XXX In principle this should only be necessary for border style changes
     // However the bc painting code tries to maximize the drawn border segments
     // so it stores in the cellmap where a new border segment starts and this
     // introduces a unwanted cellmap data dependence on color
--- a/layout/tools/reftest/Makefile.in
+++ b/layout/tools/reftest/Makefile.in
@@ -55,19 +55,19 @@ libs:: copy-harness
 endif
 
 _HARNESS_FILES = \
   $(srcdir)/runreftest.py \
   $(srcdir)/remotereftest.py \
   $(srcdir)/runreftestb2g.py \
   $(srcdir)/b2g_start_script.js \
   automation.py \
-  $(topsrcdir)/build/mobile/devicemanager.py \
-  $(topsrcdir)/build/mobile/devicemanagerADB.py \
-  $(topsrcdir)/build/mobile/devicemanagerSUT.py \
+  $(topsrcdir)/testing/mozbase/mozdevice/mozdevice/devicemanager.py \
+  $(topsrcdir)/testing/mozbase/mozdevice/mozdevice/devicemanagerADB.py \
+  $(topsrcdir)/testing/mozbase/mozdevice/mozdevice/devicemanagerSUT.py \
   $(topsrcdir)/build/mobile/b2gautomation.py \
   $(topsrcdir)/build/automationutils.py \
   $(topsrcdir)/build/mobile/remoteautomation.py \
   $(topsrcdir)/testing/mochitest/server.js \
   $(topsrcdir)/build/pgo/server-locations.txt \
   $(NULL)
 
 $(_DEST_DIR):
--- a/mobile/android/base/BrowserToolbar.java
+++ b/mobile/android/base/BrowserToolbar.java
@@ -50,16 +50,17 @@ public class BrowserToolbar implements V
                                        GeckoMenu.ActionItemBarPresenter,
                                        Animation.AnimationListener {
     private static final String LOGTAG = "GeckoToolbar";
     private LinearLayout mLayout;
     private Button mAwesomeBar;
     private TextView mTitle;
     private int mTitlePadding;
     private boolean mSiteSecurityVisible;
+    private boolean mAnimateSiteSecurity;
     private ImageButton mTabs;
     private ImageView mBack;
     private ImageView mForward;
     public ImageButton mFavicon;
     public ImageButton mStop;
     public ImageButton mSiteSecurity;
     public ImageButton mReader;
     private AnimationDrawable mProgressSpinner;
@@ -97,16 +98,17 @@ public class BrowserToolbar implements V
 
     public BrowserToolbar(BrowserApp activity) {
         // BrowserToolbar is attached to BrowserApp only.
         mActivity = activity;
         mInflater = LayoutInflater.from(activity);
 
         sActionItems = new ArrayList<View>();
         Tabs.registerOnTabsChangedListener(this);
+        mAnimateSiteSecurity = true;
     }
 
     public void from(LinearLayout layout) {
         mLayout = layout;
 
         mShowSiteSecurity = false;
         mShowReader = false;
 
@@ -339,21 +341,26 @@ public class BrowserToolbar implements V
                 if (Tabs.getInstance().isSelectedTab(tab)) {
                     updateBackButton(tab.canDoBack());
                     updateForwardButton(tab.canDoForward());
                     setProgressVisibility(false);
                 }
                 break;
             case RESTORED:
             case SELECTED:
+                // We should not animate the lock icon when switching or
+                // restoring tabs.
+                mAnimateSiteSecurity = false;
+                // fall through
             case LOCATION_CHANGE:
             case LOAD_ERROR:
                 if (Tabs.getInstance().isSelectedTab(tab)) {
                     refresh();
                 }
+                mAnimateSiteSecurity = true;
                 break;
             case CLOSED:
             case ADDED:
                 updateTabCountAndAnimate(Tabs.getInstance().getCount());
                 updateBackButton(false);
                 updateForwardButton(false);
                 break;
         }
@@ -502,16 +509,21 @@ public class BrowserToolbar implements V
     }
 
     private void setSiteSecurityVisibility(final boolean visible) {
         if (visible == mSiteSecurityVisible)
             return;
 
         mSiteSecurityVisible = visible;
 
+        if (!mAnimateSiteSecurity) {
+            mSiteSecurity.setVisibility(visible ? View.VISIBLE : View.GONE);
+            return;
+        }
+
         mTitle.clearAnimation();
         mSiteSecurity.clearAnimation();
 
         // If any of these animations were cancelled as a result of the
         // clearAnimation() calls above, we need to reset them.
         mLockFadeIn.reset();
         mTitleSlideLeft.reset();
         mTitleSlideRight.reset();
--- a/modules/libpref/src/init/all.js
+++ b/modules/libpref/src/init/all.js
@@ -3537,18 +3537,16 @@ pref("image.mem.max_ms_before_yield", 5)
 // The maximum amount of decoded image data we'll willingly keep around (we
 // might keep around more than this, but we'll try to get down to this value).
 pref("image.mem.max_decoded_image_kb", 51200);
 
 // WebGL prefs
 pref("webgl.force-enabled", false);
 pref("webgl.disabled", false);
 pref("webgl.shader_validator", true);
-pref("webgl.force_osmesa", false);
-pref("webgl.osmesalib", "");
 pref("webgl.prefer-native-gl", false);
 pref("webgl.min_capability_mode", false);
 pref("webgl.disable-extensions", false);
 pref("webgl.msaa-level", 2);
 pref("webgl.msaa-force", false);
 pref("webgl.prefer-16bpp", false);
 pref("webgl.default-no-alpha", false);
 pref("webgl.force-layers-readback", false);
--- a/testing/mochitest/Makefile.in
+++ b/testing/mochitest/Makefile.in
@@ -45,19 +45,19 @@ include $(topsrcdir)/build/automation-bu
 
 # files that get copied into $objdir/_tests/
 _SERV_FILES = 	\
 		runtests.py \
 		automation.py \
 		runtestsb2g.py \
 		runtestsremote.py \
 		runtestsvmware.py \
-		$(topsrcdir)/build/mobile/devicemanager.py \
-		$(topsrcdir)/build/mobile/devicemanagerADB.py \
-		$(topsrcdir)/build/mobile/devicemanagerSUT.py \
+		$(topsrcdir)/testing/mozbase/mozdevice/mozdevice/devicemanager.py \
+		$(topsrcdir)/testing/mozbase/mozdevice/mozdevice/devicemanagerADB.py \
+		$(topsrcdir)/testing/mozbase/mozdevice/mozdevice/devicemanagerSUT.py \
 		$(topsrcdir)/build/automationutils.py \
 		$(topsrcdir)/build/manifestparser.py \
 		$(topsrcdir)/build/mobile/remoteautomation.py \
 		$(topsrcdir)/build/mobile/b2gautomation.py \
 		gen_template.pl \
 		server.js \
 		harness-overlay.xul \
 		harness.xul \
--- a/testing/mozbase/manifestdestiny/README.md
+++ b/testing/mozbase/manifestdestiny/README.md
@@ -5,25 +5,24 @@ Universal manifests for Mozilla test har
 What ManifestDestiny gives you:
 
 * manifests are ordered lists of tests
 * tests may have an arbitrary number of key, value pairs
 * the parser returns an ordered list of test data structures, which
   are just dicts with some keys.  For example, a test with no
   user-specified metadata looks like this:
 
-    [{'path':
-      '/home/jhammel/mozmill/src/ManifestDestiny/manifestdestiny/tests/testToolbar/testBackForwardButtons.js',
-      'name': 'testToolbar/testBackForwardButtons.js', 'here':
-      '/home/jhammel/mozmill/src/ManifestDestiny/manifestdestiny/tests',
-      'manifest': '/home/jhammel/mozmill/src/ManifestDestiny/manifestdestiny/tests',}]
+    [{'expected': 'pass',
+      'path': '/home/mozilla/mozmill/src/ManifestDestiny/manifestdestiny/tests/testToolbar/testBackForwardButtons.js',
+      'relpath': 'testToolbar/testBackForwardButtons.js',
+      'name': 'testBackForwardButtons.js',
+      'here': '/home/mozilla/mozmill/src/ManifestDestiny/manifestdestiny/tests',
+      'manifest': '/home/mozilla/mozmill/src/ManifestDestiny/manifestdestiny/tests/manifest.ini',}]
 
-The keys displayed here (path, name, here, and manifest) are reserved
-keys for ManifestDestiny and any consuming APIs.  You can add
-additional key, value metadata to each test.
+The keys displayed here (path, relpath, name, here, and manifest) are reserved keys for ManifestDestiny and any consuming APIs.  You can add additional key, value metadata to each test.
 
 
 # Why have test manifests?
 
 It is desirable to have a unified format for test manifests for testing
 [mozilla-central](http://hg.mozilla.org/mozilla-central), etc.
 
 * It is desirable to be able to selectively enable or disable tests based on platform or other conditions. This should be easy to do. Currently, since many of the harnesses just crawl directories, there is no effective way of disabling a test except for removal from mozilla-central
@@ -105,18 +104,18 @@ the `[include:]` directive unless they a
 
 
 # Data
 
 Manifest Destiny gives tests as a list of dictionaries (in python
 terms).
 
 * path: full path to the test
-* name: short name of the test; this is the (usually) relative path
-  specified in the section name
+* relpath: relative path starting from the root manifest location
+* name: file name of the test
 * here: the parent directory of the manifest
 * manifest: the path to the manifest containing the test
 
 This data corresponds to a one-line manifest:
 
     [testToolbar/testBackForwardButtons.js]
 
 If additional key, values were specified, they would be in this dict
--- a/testing/mozbase/manifestdestiny/manifestparser/manifestparser.py
+++ b/testing/mozbase/manifestdestiny/manifestparser/manifestparser.py
@@ -395,16 +395,65 @@ class ManifestParser(object):
         self.rootdir = None
         self.relativeRoot = None
         if manifests:
             self.read(*manifests)
 
     def getRelativeRoot(self, root):
         return root
 
+    def _read(self, root, filename, defaults):
+
+        # get directory of this file
+        here = os.path.dirname(os.path.abspath(filename))
+        defaults['here'] = here
+
+        # read the configuration
+        sections = read_ini(fp=filename, variables=defaults, strict=self.strict)
+
+        # get the tests
+        for section, data in sections:
+
+            # a file to include
+            # TODO: keep track of included file structure:
+            # self.manifests = {'manifest.ini': 'relative/path.ini'}
+            if section.startswith('include:'):
+                include_file = section.split('include:', 1)[-1]
+                include_file = normalize_path(include_file)
+                if not os.path.isabs(include_file):
+                    include_file = os.path.join(self.getRelativeRoot(here), include_file)
+                if not os.path.exists(include_file):
+                    if self.strict:
+                        raise IOError("File '%s' does not exist" % include_file)
+                    else:
+                        continue
+                include_defaults = data.copy()
+                self._read(root, include_file, include_defaults)
+                continue
+
+            # otherwise an item
+            test = data
+            test['name'] = section
+            test['manifest'] = os.path.abspath(filename)
+
+            # determine the path
+            path = test.get('path', section)
+            relpath = path
+            if '://' not in path: # don't futz with URLs
+                path = normalize_path(path)
+                if not os.path.isabs(path):
+                    path = os.path.join(here, path)
+                relpath = os.path.relpath(path, self.rootdir)
+
+            test['path'] = path
+            test['relpath'] = relpath
+
+            # append the item
+            self.tests.append(test)
+
     def read(self, *filenames, **defaults):
 
         # ensure all files exist
         missing = [ filename for filename in filenames
                     if not os.path.exists(filename) ]
         if missing:
             raise IOError('Missing files: %s' % ', '.join(missing))
 
@@ -416,54 +465,17 @@ class ManifestParser(object):
             here = os.path.dirname(os.path.abspath(filename))
             defaults['here'] = here
 
             if self.rootdir is None:
                 # set the root directory
                 # == the directory of the first manifest given
                 self.rootdir = here
 
-            # read the configuration
-            sections = read_ini(fp=filename, variables=defaults, strict=self.strict)
-
-            # get the tests
-            for section, data in sections:
-
-                # a file to include
-                # TODO: keep track of included file structure:
-                # self.manifests = {'manifest.ini': 'relative/path.ini'}
-                if section.startswith('include:'):
-                    include_file = section.split('include:', 1)[-1]
-                    include_file = normalize_path(include_file)
-                    if not os.path.isabs(include_file):
-                        include_file = os.path.join(self.getRelativeRoot(here), include_file)
-                    if not os.path.exists(include_file):
-                        if self.strict:
-                            raise IOError("File '%s' does not exist" % include_file)
-                        else:
-                            continue
-                    include_defaults = data.copy()
-                    self.read(include_file, **include_defaults)
-                    continue
-
-                # otherwise an item
-                test = data
-                test['name'] = section
-                test['manifest'] = os.path.abspath(filename)
-
-                # determine the path
-                path = test.get('path', section)
-                if '://' not in path: # don't futz with URLs
-                    path = normalize_path(path)
-                    if not os.path.isabs(path):
-                        path = os.path.join(here, path)
-                test['path'] = path
-
-                # append the item
-                self.tests.append(test)
+            self._read(here, filename, defaults)
 
     ### methods for querying manifests
 
     def query(self, *checks, **kw):
         """
         general query function for tests
         - checks : callable conditions to test if the test fulfills the query
         """
@@ -590,17 +602,17 @@ class ManifestParser(object):
             if not os.path.isabs(path):
                 path = test['path']
                 if self.rootdir:
                     path = relpath(test['path'], self.rootdir)
                 path = denormalize_path(path)
             print >> fp, '[%s]' % path
 
             # reserved keywords:
-            reserved = ['path', 'name', 'here', 'manifest']
+            reserved = ['path', 'name', 'here', 'manifest', 'relpath']
             for key in sorted(test.keys()):
                 if key in reserved:
                     continue
                 if key in global_kwargs:
                     continue
                 if key in global_tags and not test[key]:
                     continue
                 print >> fp, '%s = %s' % (key, test[key])
@@ -1007,17 +1019,17 @@ commands = { 'create': CreateCLI,
              'update': UpdateCLI,
              'write': WriteCLI }
 
 def main(args=sys.argv[1:]):
     """console_script entry point"""
 
     # set up an option parser
     usage = '%prog [options] [command] ...'
-    description = __doc__
+    description = "%s. Use `help` to display commands" % __doc__.strip()
     parser = OptionParser(usage=usage, description=description)
     parser.add_option('-s', '--strict', dest='strict',
                       action='store_true', default=False,
                       help='adhere strictly to errors')
     parser.disable_interspersed_args()
 
     options, args = parser.parse_args(args)
 
--- a/testing/mozbase/manifestdestiny/setup.py
+++ b/testing/mozbase/manifestdestiny/setup.py
@@ -1,43 +1,36 @@
 # 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/.
 
-# The real details are in manifestparser.py; this is just a front-end
-# BUT use this file when you want to distribute to python!
-# otherwise setuptools will complain that it can't find setup.py
-# and result in a useless package
-
-from setuptools import setup, find_packages
+from setuptools import setup
 import sys
 import os
 
 here = os.path.dirname(os.path.abspath(__file__))
 try:
     filename = os.path.join(here, 'README.md')
     description = file(filename).read()
 except:
     description = ''
 
 PACKAGE_NAME = "ManifestDestiny"
-PACKAGE_VERSION = "0.5.4"
+PACKAGE_VERSION = '0.5.5'
 
 setup(name=PACKAGE_NAME,
       version=PACKAGE_VERSION,
       description="Universal manifests for Mozilla test harnesses",
       long_description=description,
       classifiers=[], # Get strings from http://pypi.python.org/pypi?%3Aaction=list_classifiers
       keywords='mozilla manifests',
-      author='Jeff Hammel',
-      author_email='jhammel@mozilla.com',
-      url='https://github.com/mozilla/mozbase/tree/master/manifestdestiny',
+      author='Mozilla Automation and Testing Team',
+      author_email='tools@lists.mozilla.org',
+      url='https://wiki.mozilla.org/Auto-tools/Projects/MozBase',
       license='MPL',
       zip_safe=False,
-      packages=find_packages(exclude=['legacy']),
-      install_requires=[
-      # -*- Extra requirements: -*-
-      ],
+      packages=['manifestparser'],
+      install_requires=[],
       entry_points="""
       [console_scripts]
-      manifestparser = manifestparser:main
+      manifestparser = manifestparser.manifestparser:main
       """,
      )
new file mode 100644
--- /dev/null
+++ b/testing/mozbase/manifestdestiny/tests/manifest.ini
@@ -0,0 +1,4 @@
+# test manifest for mozbase tests
+[test_expressionparser.py]
+[test_manifestparser.py]
+[test_testmanifest.py]
deleted file mode 100755
--- a/testing/mozbase/manifestdestiny/tests/test.py
+++ /dev/null
@@ -1,81 +0,0 @@
-#!/usr/bin/env python
-
-# 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/.
-
-"""tests for ManifestDestiny"""
-
-import doctest
-import os
-import sys
-from optparse import OptionParser
-
-def run_tests(raise_on_error=False, report_first=False):
-
-    # add results here
-    results = {}
-
-    # doctest arguments
-    directory = os.path.dirname(os.path.abspath(__file__))
-    extraglobs = {}
-    doctest_args = dict(extraglobs=extraglobs,
-                        module_relative=False,
-                        raise_on_error=raise_on_error)
-    if report_first:
-        doctest_args['optionflags'] = doctest.REPORT_ONLY_FIRST_FAILURE
-
-    # gather tests
-    directory = os.path.dirname(os.path.abspath(__file__))
-    tests =  [ test for test in os.listdir(directory)
-               if test.endswith('.txt') and test.startswith('test_')]
-    os.chdir(directory)
-
-    # run the tests
-    for test in tests:
-        try:
-            results[test] = doctest.testfile(test, **doctest_args)
-        except doctest.DocTestFailure, failure:
-            raise
-        except doctest.UnexpectedException, failure:
-            raise failure.exc_info[0], failure.exc_info[1], failure.exc_info[2]
-        
-    return results
-                                
-
-def main(args=sys.argv[1:]):
-
-    # parse command line options
-    parser = OptionParser(description=__doc__)
-    parser.add_option('--raise', dest='raise_on_error',
-                      default=False, action='store_true',
-                      help="raise on first error")
-    parser.add_option('--report-first', dest='report_first',
-                      default=False, action='store_true',
-                      help="report the first error only (all tests will still run)")
-    parser.add_option('-q', '--quiet', dest='quiet',
-                      default=False, action='store_true',
-                      help="minimize output")
-    options, args = parser.parse_args(args)
-    quiet = options.__dict__.pop('quiet')
-
-    # run the tests
-    results = run_tests(**options.__dict__)
-
-    # check for failure
-    failed = False
-    for result in results.values():
-        if result[0]: # failure count; http://docs.python.org/library/doctest.html#basic-api
-            failed = True
-            break
-    if failed:
-        sys.exit(1) # error
-    if not quiet:
-        # print results
-        print "manifestparser.py: All tests pass!"
-        for test in sorted(results.keys()):
-            result = results[test]
-            print "%s: failed=%s, attempted=%s" % (test, result[0], result[1])
-
-if __name__ == '__main__':
-    main()
new file mode 100644
--- /dev/null
+++ b/testing/mozbase/manifestdestiny/tests/test_expressionparser.py
@@ -0,0 +1,68 @@
+#!/usr/bin/env python
+
+import unittest
+from manifestparser import parse
+
+class ExpressionParserTest(unittest.TestCase):
+    """Test the conditional expression parser."""
+
+    def test_basic(self):
+
+        self.assertEqual(parse("1"), 1)
+        self.assertEqual(parse("100"), 100)
+        self.assertEqual(parse("true"), True)
+        self.assertEqual(parse("false"), False)
+        self.assertEqual('', parse('""'))
+        self.assertEqual(parse('"foo bar"'), 'foo bar')
+        self.assertEqual(parse("'foo bar'"), 'foo bar')
+        self.assertEqual(parse("foo", foo=1), 1)
+        self.assertEqual(parse("bar", bar=True), True)
+        self.assertEqual(parse("abc123", abc123="xyz"), 'xyz')
+
+    def test_equality(self):
+
+        self.assertTrue(parse("true == true"))
+        self.assertTrue(parse("false == false"))
+        self.assertTrue(parse("1 == 1"))
+        self.assertTrue(parse("100 == 100"))
+        self.assertTrue(parse('"some text" == "some text"'))
+        self.assertTrue(parse("true != false"))
+        self.assertTrue(parse("1 != 2"))
+        self.assertTrue(parse('"text" != "other text"'))
+        self.assertTrue(parse("foo == true", foo=True))
+        self.assertTrue(parse("foo == 1", foo=1))
+        self.assertTrue(parse('foo == "bar"', foo='bar'))
+        self.assertTrue(parse("foo == bar", foo=True, bar=True))
+        self.assertTrue(parse("true == foo", foo=True))
+        self.assertTrue(parse("foo != true", foo=False))
+        self.assertTrue(parse("foo != 2", foo=1))
+        self.assertTrue(parse('foo != "bar"', foo='abc'))
+        self.assertTrue(parse("foo != bar", foo=True, bar=False))
+        self.assertTrue(parse("true != foo", foo=False))
+        self.assertTrue(parse("!false"))
+
+    def test_conjunctures(self):
+        self.assertTrue(parse("true && true"))
+        self.assertTrue(parse("true || false"))
+        self.assertFalse(parse("false || false"))
+        self.assertFalse(parse("true && false"))
+        self.assertTrue(parse("true || false && false"))
+
+    def test_parentheses(self):
+        self.assertTrue(parse("(true)"))
+        self.assertEqual(parse("(10)"), 10)
+        self.assertEqual(parse('("foo")'), 'foo')
+        self.assertEqual(parse("(foo)", foo=1), 1)
+        self.assertTrue(parse("(true == true)"), True)
+        self.assertTrue(parse("(true != false)"))
+        self.assertTrue(parse("(true && true)"))
+        self.assertTrue(parse("(true || false)"))
+        self.assertTrue(parse("(true && true || false)"))
+        self.assertFalse(parse("(true || false) && false"))
+        self.assertTrue(parse("(true || false) && true"))
+        self.assertTrue(parse("true && (true || false)"))
+        self.assertTrue(parse("true && (true || false)"))
+        self.assertTrue(parse("(true && false) || (true && (true || false))"))
+
+if __name__ == '__main__':
+    unittest.main()
deleted file mode 100644
--- a/testing/mozbase/manifestdestiny/tests/test_expressionparser.txt
+++ /dev/null
@@ -1,118 +0,0 @@
-Test Expressionparser
-=====================
-
-Test the conditional expression parser.
-
-Boilerplate::
-
-    >>> from manifestparser import parse
-
-Test basic values::
-
-    >>> parse("1")
-    1
-    >>> parse("100")
-    100
-    >>> parse("true")
-    True
-    >>> parse("false")
-    False
-    >>> '' == parse('""')
-    True
-    >>> parse('"foo bar"')
-    'foo bar'
-    >>> parse("'foo bar'")
-    'foo bar'
-    >>> parse("foo", foo=1)
-    1
-    >>> parse("bar", bar=True)
-    True
-    >>> parse("abc123", abc123="xyz")
-    'xyz'
-
-Test equality::
-
-    >>> parse("true == true")
-    True
-    >>> parse("false == false")
-    True
-    >>> parse("1 == 1")
-    True
-    >>> parse("100 == 100")
-    True
-    >>> parse('"some text" == "some text"')
-    True
-    >>> parse("true != false")
-    True
-    >>> parse("1 != 2")
-    True
-    >>> parse('"text" != "other text"')
-    True
-    >>> parse("foo == true", foo=True)
-    True
-    >>> parse("foo == 1", foo=1)
-    True
-    >>> parse('foo == "bar"', foo='bar')
-    True
-    >>> parse("foo == bar", foo=True, bar=True)
-    True
-    >>> parse("true == foo", foo=True)
-    True
-    >>> parse("foo != true", foo=False)
-    True
-    >>> parse("foo != 2", foo=1)
-    True
-    >>> parse('foo != "bar"', foo='abc')
-    True
-    >>> parse("foo != bar", foo=True, bar=False)
-    True
-    >>> parse("true != foo", foo=False)
-    True
-    >>> parse("!false")
-    True
-
-Test conjunctions::
-    
-    >>> parse("true && true")
-    True
-    >>> parse("true || false")
-    True
-    >>> parse("false || false")
-    False
-    >>> parse("true && false")
-    False
-    >>> parse("true || false && false")
-    True
-
-Test parentheses::
-    
-    >>> parse("(true)")
-    True
-    >>> parse("(10)")
-    10
-    >>> parse('("foo")')
-    'foo'
-    >>> parse("(foo)", foo=1)
-    1
-    >>> parse("(true == true)")
-    True
-    >>> parse("(true != false)")
-    True
-    >>> parse("(true && true)")
-    True
-    >>> parse("(true || false)")
-    True
-    >>> parse("(true && true || false)")
-    True
-    >>> parse("(true || false) && false")
-    False
-    >>> parse("(true || false) && true")
-    True
-    >>> parse("true && (true || false)")
-    True
-    >>> parse("true && (true || false)")
-    True
-    >>> parse("(true && false) || (true && (true || false))")
-    True
-        
-
new file mode 100644
--- /dev/null
+++ b/testing/mozbase/manifestdestiny/tests/test_manifestparser.py
@@ -0,0 +1,219 @@
+#!/usr/bin/env python
+
+import os
+import shutil
+import tempfile
+import unittest
+from manifestparser import convert
+from manifestparser import ManifestParser
+from StringIO import StringIO
+
+here = os.path.dirname(os.path.abspath(__file__))
+
+class TestManifestparser(unittest.TestCase):
+    """
+    Test the manifest parser
+
+    You must have ManifestDestiny installed before running these tests.
+    Run ``python manifestparser.py setup develop`` with setuptools installed.
+    """
+
+    def test_sanity(self):
+        """Ensure basic parser is sane"""
+
+        parser = ManifestParser()
+        mozmill_example = os.path.join(here, 'mozmill-example.ini')
+        parser.read(mozmill_example)
+        tests = parser.tests
+        self.assertEqual(len(tests), len(file(mozmill_example).read().strip().splitlines()))
+
+        # Ensure that capitalization and order aren't an issue:
+        lines = ['[%s]' % test['name'] for test in tests]
+        self.assertEqual(lines, file(mozmill_example).read().strip().splitlines())
+
+        # Show how you select subsets of tests:
+        mozmill_restart_example = os.path.join(here, 'mozmill-restart-example.ini')
+        parser.read(mozmill_restart_example)
+        restart_tests = parser.get(type='restart')
+        self.assertTrue(len(restart_tests) < len(parser.tests))
+        self.assertEqual(len(restart_tests), len(parser.get(manifest=mozmill_restart_example)))
+        self.assertFalse([test for test in restart_tests
+                          if test['manifest'] != os.path.join(here, 'mozmill-restart-example.ini')])
+        self.assertEqual(parser.get('name', tags=['foo']),
+                         ['restartTests/testExtensionInstallUninstall/test2.js',
+                          'restartTests/testExtensionInstallUninstall/test1.js'])
+        self.assertEqual(parser.get('name', foo='bar'),
+                         ['restartTests/testExtensionInstallUninstall/test2.js'])
+
+    def test_include(self):
+        """Illustrate how include works"""
+
+        include_example = os.path.join(here, 'include-example.ini')
+        parser = ManifestParser(manifests=(include_example,))
+
+        # All of the tests should be included, in order:
+        self.assertEqual(parser.get('name'),
+                         ['crash-handling', 'fleem', 'flowers'])
+        self.assertEqual([(test['name'], os.path.basename(test['manifest'])) for test in parser.tests],
+                         [('crash-handling', 'bar.ini'), ('fleem', 'include-example.ini'), ('flowers', 'foo.ini')])
+
+
+        # The manifests should be there too:
+        self.assertEqual(len(parser.manifests()), 3)
+
+        # We already have the root directory:
+        self.assertEqual(here, parser.rootdir)
+
+
+        # DEFAULT values should persist across includes, unless they're
+        # overwritten.  In this example, include-example.ini sets foo=bar, but
+        # it's overridden to fleem in bar.ini
+        self.assertEqual(parser.get('name', foo='bar'),
+                         ['fleem', 'flowers'])
+        self.assertEqual(parser.get('name', foo='fleem'),
+                         ['crash-handling'])
+
+        # Passing parameters in the include section allows defining variables in
+        #the submodule scope:
+        self.assertEqual(parser.get('name', tags=['red']),
+                         ['flowers'])
+
+        # However, this should be overridable from the DEFAULT section in the
+        # included file and that overridable via the key directly connected to
+        # the test:
+        self.assertEqual(parser.get(name='flowers')[0]['blue'],
+                         'ocean')
+        self.assertEqual(parser.get(name='flowers')[0]['yellow'],
+                         'submarine')
+
+        # You can query multiple times if you need to::
+        flowers = parser.get(foo='bar')
+        self.assertEqual(len(flowers), 2)
+
+        # Using the inverse flag should invert the set of tests returned:
+        self.assertEqual(parser.get('name', inverse=True, tags=['red']),
+                         ['crash-handling', 'fleem'])
+
+        # All of the included tests actually exist::
+        self.assertEqual([i['name'] for i in parser.missing()], [])
+
+        # Write the output to a manifest:
+        buffer = StringIO()
+        parser.write(fp=buffer, global_kwargs={'foo': 'bar'})
+        self.assertEqual(buffer.getvalue().strip(),
+                         '[DEFAULT]\nfoo = bar\n\n[fleem]\n\n[include/flowers]\nblue = ocean\nred = roses\nyellow = submarine')
+
+
+    def test_directory_to_manifest(self):
+        """
+        Test our ability to convert a static directory structure to a
+        manifest.
+        """
+
+        # First, stub out a directory with files in it::
+        def create_stub():
+            directory = tempfile.mkdtemp()
+            for i in 'foo', 'bar', 'fleem':
+                file(os.path.join(directory, i), 'w').write(i)
+            subdir = os.path.join(directory, 'subdir')
+            os.mkdir(subdir)
+            file(os.path.join(subdir, 'subfile'), 'w').write('baz')
+            return directory
+        stub = create_stub()
+        self.assertTrue(os.path.exists(stub) and os.path.isdir(stub))
+
+        # Make a manifest for it:
+        self.assertEqual(convert([stub]),
+                         """[bar]
+[fleem]
+[foo]
+[subdir/subfile]""")
+        shutil.rmtree(stub) # cleanup
+
+        # Now do the same thing but keep the manifests in place:
+        stub = create_stub()
+        convert([stub], write='manifest.ini')
+        self.assertEqual(sorted(os.listdir(stub)),
+                         ['bar', 'fleem', 'foo', 'manifest.ini', 'subdir'])
+        parser = ManifestParser()
+        parser.read(os.path.join(stub, 'manifest.ini'))
+        self.assertEqual([i['name'] for i in parser.tests],
+                         ['subfile', 'bar', 'fleem', 'foo'])
+        parser = ManifestParser()
+        parser.read(os.path.join(stub, 'subdir', 'manifest.ini'))
+        self.assertEqual(len(parser.tests), 1)
+        self.assertEqual(parser.tests[0]['name'], 'subfile')
+        shutil.rmtree(stub)
+
+
+    def test_copy(self):
+        """Test our ability to copy a set of manifests"""
+
+        tempdir = tempfile.mkdtemp()
+        include_example = os.path.join(here, 'include-example.ini')
+        manifest = ManifestParser(manifests=(include_example,))
+        manifest.copy(tempdir)
+        self.assertEqual(sorted(os.listdir(tempdir)),
+                         ['fleem', 'include', 'include-example.ini'])
+        self.assertEqual(sorted(os.listdir(os.path.join(tempdir, 'include'))),
+                         ['bar.ini', 'crash-handling', 'flowers', 'foo.ini'])
+        from_manifest = ManifestParser(manifests=(include_example,))
+        to_manifest = os.path.join(tempdir, 'include-example.ini')
+        to_manifest = ManifestParser(manifests=(to_manifest,))
+        self.assertEqual(to_manifest.get('name'), from_manifest.get('name'))
+        shutil.rmtree(tempdir)
+
+
+    def test_update(self):
+        """
+        Test our ability to update tests from a manifest and a directory of
+        files
+        """
+
+        # boilerplate
+        tempdir = tempfile.mkdtemp()
+        for i in range(10):
+            file(os.path.join(tempdir, str(i)), 'w').write(str(i))
+
+        # First, make a manifest:
+        manifest = convert([tempdir])
+        newtempdir = tempfile.mkdtemp()
+        manifest_file = os.path.join(newtempdir, 'manifest.ini')
+        file(manifest_file,'w').write(manifest)
+        manifest = ManifestParser(manifests=(manifest_file,))
+        self.assertEqual(manifest.get('name'),
+                         [str(i) for i in range(10)])
+
+        # All of the tests are initially missing:
+        self.assertEqual([i['name'] for i in manifest.missing()],
+                         [str(i) for i in range(10)])
+
+        # But then we copy one over:
+        self.assertEqual(manifest.get('name', name='1'), ['1'])
+        manifest.update(tempdir, name='1')
+        self.assertEqual(sorted(os.listdir(newtempdir)),
+                         ['1', 'manifest.ini'])
+
+        # Update that one file and copy all the "tests":
+        file(os.path.join(tempdir, '1'), 'w').write('secret door')
+        manifest.update(tempdir)
+        self.assertEqual(sorted(os.listdir(newtempdir)),
+                         ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'manifest.ini'])
+        self.assertEqual(file(os.path.join(newtempdir, '1')).read().strip(),
+                         'secret door')
+
+        # clean up:
+        shutil.rmtree(tempdir)
+        shutil.rmtree(newtempdir)
+
+    def test_path_override(self):
+        """You can override the path in the section too.
+        This shows that you can use a relative path"""
+        path_example = os.path.join(here, 'path-example.ini')
+        manifest = ManifestParser(manifests=(path_example,))
+        self.assertEqual(manifest.tests[0]['path'],
+                         os.path.join(here, 'fleem'))
+
+
+if __name__ == '__main__':
+    unittest.main()
deleted file mode 100644
--- a/testing/mozbase/manifestdestiny/tests/test_manifestparser.txt
+++ /dev/null
@@ -1,217 +0,0 @@
-Test the manifest parser
-========================
-
-You must have ManifestDestiny installed before running these tests.
-Run ``python manifestparser.py setup develop`` with setuptools installed.
-
-Ensure basic parser is sane::
-
-    >>> from manifestparser import ManifestParser
-    >>> parser = ManifestParser()
-    >>> parser.read('mozmill-example.ini')
-    >>> tests = parser.tests
-    >>> len(tests) == len(file('mozmill-example.ini').read().strip().splitlines())
-    True
-    
-Ensure that capitalization and order aren't an issue:
-
-    >>> lines = ['[%s]' % test['name'] for test in tests]
-    >>> lines == file('mozmill-example.ini').read().strip().splitlines()
-    True
-
-Show how you select subsets of tests:
-
-    >>> parser.read('mozmill-restart-example.ini')
-    >>> restart_tests = parser.get(type='restart')
-    >>> len(restart_tests) < len(parser.tests)
-    True
-    >>> import os
-    >>> len(restart_tests) == len(parser.get(manifest=os.path.abspath('mozmill-restart-example.ini')))
-    True
-    >>> assert not [test for test in restart_tests if test['manifest'] != os.path.abspath('mozmill-restart-example.ini')]
-    >>> parser.get('name', tags=['foo'])
-    ['restartTests/testExtensionInstallUninstall/test2.js', 'restartTests/testExtensionInstallUninstall/test1.js']
-    >>> parser.get('name', foo='bar')
-    ['restartTests/testExtensionInstallUninstall/test2.js']
-
-Illustrate how include works::
-
-    >>> parser = ManifestParser(manifests=('include-example.ini',))
-
-All of the tests should be included, in order::
-
-    >>> parser.get('name')
-    ['crash-handling', 'fleem', 'flowers']
-    >>> [(test['name'], os.path.basename(test['manifest'])) for test in parser.tests]
-    [('crash-handling', 'bar.ini'), ('fleem', 'include-example.ini'), ('flowers', 'foo.ini')]
-
-The manifests should be there too::
-
-    >>> len(parser.manifests())
-    3
-
-We're already in the root directory::
-
-    >>> os.getcwd() == parser.rootdir
-    True
-
-DEFAULT values should persist across includes, unless they're
-overwritten.  In this example, include-example.ini sets foo=bar, but
-its overridden to fleem in bar.ini::
-
-    >>> parser.get('name', foo='bar')
-    ['fleem', 'flowers']
-    >>> parser.get('name', foo='fleem')
-    ['crash-handling']
-
-Passing parameters in the include section allows defining variables in
-the submodule scope:
-
-    >>> parser.get('name', tags=['red'])
-    ['flowers']
-
-However, this should be overridable from the DEFAULT section in the
-included file and that overridable via the key directly connected to
-the test::
-
-    >>> parser.get(name='flowers')[0]['blue']
-    'ocean'
-    >>> parser.get(name='flowers')[0]['yellow']
-    'submarine'
-
-You can query multiple times if you need to::
-
-    >>> flowers = parser.get(foo='bar')
-    >>> len(flowers)
-    2
-    >>> roses = parser.get(tests=flowers, red='roses')
-
-Using the inverse flag should invert the set of tests returned::
-
-    >>> parser.get('name', inverse=True, tags=['red'])
-    ['crash-handling', 'fleem']
-
-All of the included tests actually exist::
-
-    >>> [i['name'] for i in parser.missing()]
-    []
-
-Write the output to a manifest:
-
-    >>> from StringIO import StringIO
-    >>> buffer = StringIO()
-    >>> parser.write(fp=buffer, global_kwargs={'foo': 'bar'})
-    >>> buffer.getvalue().strip()
-    '[DEFAULT]\nfoo = bar\n\n[fleem]\n\n[include/flowers]\nblue = ocean\nred = roses\nyellow = submarine'
-
-Test our ability to convert a static directory structure to a
-manifest. First, stub out a directory with files in it::
-
-    >>> import shutil, tempfile
-    >>> def create_stub():
-    ...     directory = tempfile.mkdtemp()
-    ...     for i in 'foo', 'bar', 'fleem':
-    ...         file(os.path.join(directory, i), 'w').write(i)
-    ...     subdir = os.path.join(directory, 'subdir')
-    ...     os.mkdir(subdir)
-    ...     file(os.path.join(subdir, 'subfile'), 'w').write('baz')
-    ...     return directory
-    >>> stub = create_stub()
-    >>> os.path.exists(stub) and os.path.isdir(stub)
-    True
-
-Make a manifest for it::
-
-    >>> from manifestparser import convert
-    >>> print convert([stub])
-    [bar]
-    [fleem]
-    [foo]
-    [subdir/subfile]
-    >>> shutil.rmtree(stub)
-
-Now do the same thing but keep the manifests in place::
-
-    >>> stub = create_stub()
-    >>> convert([stub], write='manifest.ini')
-    >>> sorted(os.listdir(stub))
-    ['bar', 'fleem', 'foo', 'manifest.ini', 'subdir']
-    >>> parser = ManifestParser()
-    >>> parser.read(os.path.join(stub, 'manifest.ini'))
-    >>> [i['name'] for i in parser.tests]
-    ['subfile', 'bar', 'fleem', 'foo']
-    >>> parser = ManifestParser()
-    >>> parser.read(os.path.join(stub, 'subdir', 'manifest.ini'))
-    >>> len(parser.tests)
-    1
-    >>> parser.tests[0]['name']
-    'subfile'
-    >>> shutil.rmtree(stub)
-
-Test our ability to copy a set of manifests::
-
-    >>> tempdir = tempfile.mkdtemp()
-    >>> manifest = ManifestParser(manifests=('include-example.ini',))
-    >>> manifest.copy(tempdir)
-    >>> sorted(os.listdir(tempdir))
-    ['fleem', 'include', 'include-example.ini']
-    >>> sorted(os.listdir(os.path.join(tempdir, 'include')))
-    ['bar.ini', 'crash-handling', 'flowers', 'foo.ini']
-    >>> from_manifest = ManifestParser(manifests=('include-example.ini',))
-    >>> to_manifest = os.path.join(tempdir, 'include-example.ini')
-    >>> to_manifest = ManifestParser(manifests=(to_manifest,))
-    >>> to_manifest.get('name') == from_manifest.get('name')
-    True
-    >>> shutil.rmtree(tempdir)
-
-Test our ability to update tests from a manifest and a directory of
-files::
-
-    >>> tempdir = tempfile.mkdtemp()
-    >>> for i in range(10):
-    ...     file(os.path.join(tempdir, str(i)), 'w').write(str(i))
-
-First, make a manifest::
-
-    >>> manifest = convert([tempdir])
-    >>> newtempdir = tempfile.mkdtemp()
-    >>> manifest_file = os.path.join(newtempdir, 'manifest.ini')
-    >>> file(manifest_file,'w').write(manifest)
-    >>> manifest = ManifestParser(manifests=(manifest_file,))
-    >>> manifest.get('name') == [str(i) for i in range(10)]
-    True
-
-All of the tests are initially missing::
-
-    >>> [i['name'] for i in manifest.missing()] == [str(i) for i in range(10)]
-    True
-
-But then we copy one over::
-
-    >>> manifest.get('name', name='1')
-    ['1']
-    >>> manifest.update(tempdir, name='1')
-    >>> sorted(os.listdir(newtempdir))
-    ['1', 'manifest.ini']
-
-Update that one file and copy all the "tests"::
-   
-    >>> file(os.path.join(tempdir, '1'), 'w').write('secret door')
-    >>> manifest.update(tempdir)
-    >>> sorted(os.listdir(newtempdir))
-    ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'manifest.ini']
-    >>> file(os.path.join(newtempdir, '1')).read().strip()
-    'secret door'
-
-Clean up::
-
-    >>> shutil.rmtree(tempdir)
-    >>> shutil.rmtree(newtempdir)
-
-You can override the path in the section too.  This shows that you can
-use a relative path::
-
-    >>> manifest = ManifestParser(manifests=('path-example.ini',))
-    >>> manifest.tests[0]['path'] == os.path.abspath('fleem')
-    True
-
new file mode 100644
--- /dev/null
+++ b/testing/mozbase/manifestdestiny/tests/test_testmanifest.py
@@ -0,0 +1,34 @@
+#!/usr/bin/env python
+
+import os
+import unittest
+from manifestparser import TestManifest
+
+here = os.path.dirname(os.path.abspath(__file__))
+
+class TestTestManifest(unittest.TestCase):
+    """Test the Test Manifest"""
+
+    def test_testmanifest(self):
+        # Test filtering based on platform:
+        filter_example = os.path.join(here, 'filter-example.ini')
+        manifest = TestManifest(manifests=(filter_example,))
+        self.assertEqual([i['name'] for i in manifest.active_tests(os='win', disabled=False, exists=False)],
+                         ['windowstest', 'fleem'])
+        self.assertEqual([i['name'] for i in manifest.active_tests(os='linux', disabled=False, exists=False)],
+                         ['fleem', 'linuxtest'])
+
+        # Look for existing tests.  There is only one:
+        self.assertEqual([i['name'] for i in manifest.active_tests()],
+                         ['fleem'])
+
+        # You should be able to expect failures:
+        last_test = manifest.active_tests(exists=False, toolkit='gtk2')[-1]
+        self.assertEqual(last_test['name'], 'linuxtest')
+        self.assertEqual(last_test['expected'], 'pass')
+        last_test = manifest.active_tests(exists=False, toolkit='cocoa')[-1]
+        self.assertEqual(last_test['expected'], 'fail')
+
+
+if __name__ == '__main__':
+    unittest.main()
deleted file mode 100644
--- a/testing/mozbase/manifestdestiny/tests/test_testmanifest.txt
+++ /dev/null
@@ -1,32 +0,0 @@
-Test the Test Manifest
-======================
-
-Boilerplate::
-
-    >>> import os
-
-Test filtering based on platform::
-
-    >>> from manifestparser import TestManifest
-    >>> manifest = TestManifest(manifests=('filter-example.ini',))
-    >>> [i['name'] for i in manifest.active_tests(os='win', disabled=False, exists=False)]
-    ['windowstest', 'fleem']
-    >>> [i['name'] for i in manifest.active_tests(os='linux', disabled=False, exists=False)]
-    ['fleem', 'linuxtest']
-
-Look for existing tests.  There is only one::
-
-    >>> [i['name'] for i in manifest.active_tests()]
-    ['fleem']
-
-You should be able to expect failures::
-
-    >>> last_test = manifest.active_tests(exists=False, toolkit='gtk2')[-1]
-    >>> last_test['name']
-    'linuxtest'
-    >>> last_test['expected']
-    'pass'
-    >>> last_test = manifest.active_tests(exists=False, toolkit='cocoa')[-1]
-    >>> last_test['expected']
-    'fail'
-
new file mode 100644
--- /dev/null
+++ b/testing/mozbase/mozcrash/README.md
@@ -0,0 +1,12 @@
+# Mozcrash
+
+Package for getting a stack trace out of processes that have crashed and left behind a minidump file using the Google Breakpad library.
+
+
+## Usage example
+
+TODO
+
+    import mozcrash
+
+    #...
new file mode 100644
--- /dev/null
+++ b/testing/mozbase/mozcrash/mozcrash/__init__.py
@@ -0,0 +1,5 @@
+# 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/.
+
+from mozcrash import *
new file mode 100644
--- /dev/null
+++ b/testing/mozbase/mozcrash/mozcrash/mozcrash.py
@@ -0,0 +1,137 @@
+# 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/.
+
+from __future__ import with_statement
+__all__ = ['check_for_crashes']
+
+import os, sys, glob, urllib2, tempfile, subprocess, shutil, urlparse, zipfile
+import mozlog
+
+def is_url(thing):
+  """
+  Return True if thing looks like a URL.
+  """
+  # We want to download URLs like http://... but not Windows paths like c:\...
+  return len(urlparse.urlparse(thing).scheme) >= 2
+
+def extractall(zip, path = None):
+    """
+    Compatibility shim for Python 2.6's ZipFile.extractall.
+    """
+    if hasattr(zip, "extractall"):
+        return zip.extractall(path)
+
+    if path is None:
+        path = os.curdir
+
+    for name in self._zipfile.namelist():
+        filename = os.path.normpath(os.path.join(path, name))
+        if name.endswith("/"):
+            os.makedirs(filename)
+        else:
+            path = os.path.split(filename)[0]
+            if not os.path.isdir(path):
+                os.makedirs(path)
+        with open(filename, "wb") as dest:
+            dest.write(zip.read(name))
+
+def check_for_crashes(dump_directory, symbols_path,
+                      stackwalk_binary=None,
+                      dump_save_path=None,
+                      test_name=None):
+    """
+    Print a stack trace for minidumps left behind by a crashing program.
+
+    Arguments:
+    dump_directory: The directory in which to look for minidumps.
+    symbols_path: The path to symbols to use for dump processing.
+                  This can either be a path to a directory
+                  containing Breakpad-format symbols, or a URL
+                  to a zip file containing a set of symbols.
+    stackwalk_binary: The path to the minidump_stackwalk binary.
+                      If not set, the environment variable
+                      MINIDUMP_STACKWALK will be checked.
+    dump_save_path: A directory in which to copy minidump files
+                    for safekeeping. If not set, the environment
+                    variable MINIDUMP_SAVE_PATH will be checked.
+    test_name: The test name to be used in log output.
+
+    Returns True if any minidumps were found, False otherwise.
+    """
+    log = mozlog.getLogger('mozcrash')
+    if stackwalk_binary is None:
+        stackwalk_binary = os.environ.get('MINIDUMP_STACKWALK', None)
+
+    # try to get the caller's filename if no test name is given
+    if test_name is None:
+        try:
+            test_name = os.path.basename(sys._getframe(1).f_code.co_filename)
+        except:
+            test_name = "unknown"
+
+    # Check preconditions
+    dumps = glob.glob(os.path.join(dump_directory, '*.dmp'))
+    if len(dumps) == 0:
+        return False
+
+    found_crash = False
+    remove_symbols = False 
+    # If our symbols are at a remote URL, download them now
+    if is_url(symbols_path):
+        log.info("Downloading symbols from: %s", symbols_path)
+        remove_symbols = True
+        # Get the symbols and write them to a temporary zipfile
+        data = urllib2.urlopen(symbols_path)
+        symbols_file = tempfile.TemporaryFile()
+        symbols_file.write(data.read())
+        # extract symbols to a temporary directory (which we'll delete after
+        # processing all crashes)
+        symbols_path = tempfile.mkdtemp()
+        zfile = zipfile.ZipFile(symbols_file, 'r')
+        extractall(zfile, symbols_path)
+        zfile.close()
+
+    try:
+        for d in dumps:
+            log.info("PROCESS-CRASH | %s | application crashed (minidump found)", test_name)
+            log.info("Crash dump filename: %s", d)
+            if symbols_path and stackwalk_binary and os.path.exists(stackwalk_binary):
+                # run minidump_stackwalk
+                p = subprocess.Popen([stackwalk_binary, d, symbols_path],
+                                     stdout=subprocess.PIPE,
+                                     stderr=subprocess.PIPE)
+                (out, err) = p.communicate()
+                if len(out) > 3:
+                    # minidump_stackwalk is chatty,
+                    # so ignore stderr when it succeeds.
+                    print out
+                else:
+                    print "stderr from minidump_stackwalk:"
+                    print err
+                if p.returncode != 0:
+                    log.error("minidump_stackwalk exited with return code %d", p.returncode)
+            else:
+                if not symbols_path:
+                    log.warn("No symbols path given, can't process dump.")
+                if not stackwalk_binary:
+                    log.warn("MINIDUMP_STACKWALK not set, can't process dump.")
+                elif stackwalk_binary and not os.path.exists(stackwalk_binary):
+                    log.warn("MINIDUMP_STACKWALK binary not found: %s", stackwalk_binary)
+            if dump_save_path is None:
+                dump_save_path = os.environ.get('MINIDUMP_SAVE_PATH', None)
+            if dump_save_path:
+                shutil.move(d, dump_save_path)
+                log.info("Saved dump as %s", os.path.join(dump_save_path,
+                                                          os.path.basename(d)))
+            else:
+                os.remove(d)
+            extra = os.path.splitext(d)[0] + ".extra"
+            if os.path.exists(extra):
+                os.remove(extra)
+            found_crash = True
+    finally:
+        if remove_symbols:
+            shutil.rmtree(symbols_path)
+
+    return found_crash
new file mode 100644
--- /dev/null
+++ b/testing/mozbase/mozcrash/setup.py
@@ -0,0 +1,35 @@
+# 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/.
+
+
+import os
+from setuptools import setup
+
+PACKAGE_VERSION = '0.1'
+
+# get documentation from the README
+try:
+    here = os.path.dirname(os.path.abspath(__file__))
+    description = file(os.path.join(here, 'README.md')).read()
+except (OSError, IOError):
+    description = ''
+
+# dependencies
+deps = ['']
+
+setup(name='mozcrash',
+      version=PACKAGE_VERSION,
+      description="Package for printing stack traces from minidumps left behind by crashed processes.",
+      long_description=description,
+      classifiers=[], # Get strings from http://pypi.python.org/pypi?%3Aaction=list_classifiers
+      keywords='mozilla',
+      author='Mozilla Automation and Tools team',
+      author_email='tools@lists.mozilla.org',
+      url='https://wiki.mozilla.org/Auto-tools/Projects/MozBase',
+      license='MPL',
+      packages=['mozcrash'],
+      include_package_data=True,
+      zip_safe=False,
+      install_requires=deps,
+      )
new file mode 100644
--- /dev/null
+++ b/testing/mozbase/mozcrash/tests/manifest.ini
@@ -0,0 +1,1 @@
+[test.py]
new file mode 100644
--- /dev/null
+++ b/testing/mozbase/mozcrash/tests/test.py
@@ -0,0 +1,136 @@
+#!/usr/bin/env python
+#
+# 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/.
+
+import os, unittest, subprocess, tempfile, shutil, urlparse, zipfile, StringIO
+import mozcrash, mozlog, mozhttpd
+
+# Make logs go away
+log = mozlog.getLogger("mozcrash", os.devnull)
+
+def popen_factory(stdouts):
+    """
+    Generate a class that can mock subprocess.Popen. |stdouts| is an iterable that
+    should return an iterable for the stdout of each process in turn.
+    """
+    class mock_popen(object):
+        def __init__(self, args, *args_rest, **kwargs):
+            self.stdout = stdouts.next()
+            self.returncode = 0
+
+        def wait(self):
+            return 0
+
+        def communicate(self):
+            return (self.stdout.next(), "")
+
+    return mock_popen
+
+class TestCrash(unittest.TestCase):
+    def setUp(self):
+        self.tempdir = tempfile.mkdtemp()
+        # a fake file to use as a stackwalk binary
+        self.stackwalk = os.path.join(self.tempdir, "stackwalk")
+        open(self.stackwalk, "w").write("fake binary")
+        self._subprocess_popen = subprocess.Popen
+        subprocess.Popen = popen_factory(self.next_mock_stdout())
+        self.stdouts = []
+
+    def tearDown(self):
+        subprocess.Popen = self._subprocess_popen
+        shutil.rmtree(self.tempdir)
+
+    def next_mock_stdout(self):
+        if not self.stdouts:
+            yield iter([])
+        for s in self.stdouts:
+            yield iter(s)
+
+    def test_nodumps(self):
+        """
+        Test that check_for_crashes returns False if no dumps are present.
+        """
+        self.stdouts.append(["this is some output"])
+        self.assertFalse(mozcrash.check_for_crashes(self.tempdir,
+                                                    'symbols_path',
+                                                    stackwalk_binary=self.stackwalk))
+
+    def test_simple(self):
+        """
+        Test that check_for_crashes returns True if a dump is present.
+        """
+        open(os.path.join(self.tempdir, "test.dmp"), "w").write("foo")
+        self.stdouts.append(["this is some output"])
+        self.assert_(mozcrash.check_for_crashes(self.tempdir,
+                                                'symbols_path',
+                                                stackwalk_binary=self.stackwalk))
+
+    def test_stackwalk_envvar(self):
+        """
+        Test that check_for_crashes uses the MINIDUMP_STACKWALK environment var.
+        """
+        open(os.path.join(self.tempdir, "test.dmp"), "w").write("foo")
+        self.stdouts.append(["this is some output"])
+        os.environ['MINIDUMP_STACKWALK'] = self.stackwalk
+        self.assert_(mozcrash.check_for_crashes(self.tempdir,
+                                                'symbols_path'))
+        del os.environ['MINIDUMP_STACKWALK']
+
+    def test_save_path(self):
+        """
+        Test that dump_save_path works.
+        """
+        open(os.path.join(self.tempdir, "test.dmp"), "w").write("foo")
+        save_path = os.path.join(self.tempdir, "saved")
+        os.mkdir(save_path)
+        self.stdouts.append(["this is some output"])
+        self.assert_(mozcrash.check_for_crashes(self.tempdir,
+                                                'symbols_path',
+                                                stackwalk_binary=self.stackwalk,
+                                                dump_save_path=save_path))
+        self.assert_(os.path.isfile(os.path.join(save_path, "test.dmp")))
+
+    def test_save_path_envvar(self):
+        """
+        Test that the MINDUMP_SAVE_PATH environment variable works.
+        """
+        open(os.path.join(self.tempdir, "test.dmp"), "w").write("foo")
+        save_path = os.path.join(self.tempdir, "saved")
+        os.mkdir(save_path)
+        self.stdouts.append(["this is some output"])
+        os.environ['MINIDUMP_SAVE_PATH'] = save_path
+        self.assert_(mozcrash.check_for_crashes(self.tempdir,
+                                                'symbols_path',
+                                                stackwalk_binary=self.stackwalk))
+        del os.environ['MINIDUMP_SAVE_PATH']
+        self.assert_(os.path.isfile(os.path.join(save_path, "test.dmp")))
+
+    def test_symbol_path_url(self):
+        """
+        Test that passing a URL as symbols_path correctly fetches the URL.
+        """
+        open(os.path.join(self.tempdir, "test.dmp"), "w").write("foo")
+        self.stdouts.append(["this is some output"])
+
+        def make_zipfile():
+            data = StringIO.StringIO()
+            z = zipfile.ZipFile(data, 'w')
+            z.writestr("symbols.txt", "abc/xyz")
+            z.close()
+            return data.getvalue()
+        def get_symbols(req):
+            headers = {}
+            return (200, headers, make_zipfile())
+        httpd = mozhttpd.MozHttpd(port=0,
+                                  urlhandlers=[{'method':'GET', 'path':'/symbols', 'function':get_symbols}])
+        httpd.start()
+        symbol_url = urlparse.urlunsplit(('http', '%s:%d' % httpd.httpd.server_address,
+                                        '/symbols','',''))
+        self.assert_(mozcrash.check_for_crashes(self.tempdir,
+                                                symbol_url,
+                                                stackwalk_binary=self.stackwalk))
+
+if __name__ == '__main__':
+    unittest.main()
new file mode 100644
--- /dev/null
+++ b/testing/mozbase/mozdevice/README.md
@@ -0,0 +1,5 @@
+[mozdevice](https://github.com/mozilla/mozbase/tree/master/mozdevice) provides
+an interface to interact with a remote device such as an Android phone connected
+to a workstation. Currently there are two implementations of the interface: one
+uses a TCP-based protocol to communicate with a server running on the device,
+another uses Android's adb utility.
new file mode 100644
--- /dev/null
+++ b/testing/mozbase/mozdevice/mozdevice/__init__.py
@@ -0,0 +1,11 @@
+# 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/.
+
+from devicemanager import DMError
+from devicemanagerADB import DeviceManagerADB
+from devicemanagerSUT import DeviceManagerSUT
+from droid import DroidADB, DroidSUT
+from emulator import Emulator
+from b2gemulator import B2GEmulator
+
new file mode 100644
--- /dev/null
+++ b/testing/mozbase/mozdevice/mozdevice/b2gemulator.py
@@ -0,0 +1,87 @@
+# 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/.
+
+
+import os
+import platform
+
+from emulator import Emulator
+
+
+class B2GEmulator(Emulator):
+
+    def __init__(self, homedir=None, noWindow=False, logcat_dir=None, arch="x86",
+                 emulatorBinary=None, res='480x800', userdata=None,
+                 memory='512', partition_size='512'):
+        super(B2GEmulator, self).__init__(noWindow=noWindow, logcat_dir=logcat_dir,
+                                          arch=arch, emulatorBinary=emulatorBinary,
+                                          res=res, userdata=userdata,
+                                          memory=memory, partition_size=partition_size)
+        self.homedir = homedir
+        if self.homedir is not None:
+            self.homedir = os.path.expanduser(homedir)
+
+    def _check_file(self, filePath):
+        if not os.path.exists(filePath):
+            raise Exception(('File not found: %s; did you pass the B2G home '
+                             'directory as the homedir parameter, or set '
+                             'B2G_HOME correctly?') % filePath)
+
+    def _check_for_adb(self, host_dir):
+        if self._default_adb() == 0:
+            return
+        adb_paths = [os.path.join(self.homedir,'glue','gonk','out','host',
+                      host_dir ,'bin','adb'),os.path.join(self.homedir, 'out',
+                      'host', host_dir,'bin','adb'),os.path.join(self.homedir,
+                      'bin','adb')]
+        for option in adb_paths:
+            if os.path.exists(option):
+                self.adb = option
+                return
+        raise Exception('adb not found!')
+
+    def _locate_files(self):
+        if self.homedir is None:
+            self.homedir = os.getenv('B2G_HOME')
+        if self.homedir is None:
+            raise Exception('Must define B2G_HOME or pass the homedir parameter')
+        self._check_file(self.homedir)
+
+        if self.arch not in ("x86", "arm"):
+            raise Exception("Emulator architecture must be one of x86, arm, got: %s" %
+                            self.arch)
+
+        host_dir = "linux-x86"
+        if platform.system() == "Darwin":
+            host_dir = "darwin-x86"
+
+        host_bin_dir = os.path.join("out", "host", host_dir, "bin")
+
+        if self.arch == "x86":
+            binary = os.path.join(host_bin_dir, "emulator-x86")
+            kernel = "prebuilts/qemu-kernel/x86/kernel-qemu"
+            sysdir = "out/target/product/generic_x86"
+            self.tail_args = []
+        else:
+            binary = os.path.join(host_bin_dir, "emulator")
+            kernel = "prebuilts/qemu-kernel/arm/kernel-qemu-armv7"
+            sysdir = "out/target/product/generic"
+            self.tail_args = ["-cpu", "cortex-a8"]
+
+        self._check_for_adb(host_dir)
+
+        if not self.binary:
+            self.binary = os.path.join(self.homedir, binary)
+
+        self._check_file(self.binary)
+
+        self.kernelImg = os.path.join(self.homedir, kernel)
+        self._check_file(self.kernelImg)
+
+        self.sysDir = os.path.join(self.homedir, sysdir)
+        self._check_file(self.sysDir)
+
+        if not self.dataImg:
+            self.dataImg = os.path.join(self.sysDir, 'userdata.img')
+        self._check_file(self.dataImg)
new file mode 100644
--- /dev/null
+++ b/testing/mozbase/mozdevice/mozdevice/devicemanager.py
@@ -0,0 +1,637 @@
+# 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/.
+
+import hashlib
+import socket
+import os
+import re
+import StringIO
+
+class FileError(Exception):
+  " Signifies an error which occurs while doing a file operation."
+
+  def __init__(self, msg = ''):
+    self.msg = msg
+
+  def __str__(self):
+    return self.msg
+
+class DMError(Exception):
+  "generic devicemanager exception."
+
+  def __init__(self, msg= ''):
+    self.msg = msg
+
+  def __str__(self):
+    return self.msg
+
+def abstractmethod(method):
+  line = method.func_code.co_firstlineno
+  filename = method.func_code.co_filename
+  def not_implemented(*args, **kwargs):
+    raise NotImplementedError('Abstract method %s at File "%s", line %s '
+                              'should be implemented by a concrete class' %
+                              (repr(method), filename,line))
+  return not_implemented
+
+class DeviceManager:
+
+  @abstractmethod
+  def shell(self, cmd, outputfile, env=None, cwd=None, timeout=None):
+    """
+    executes shell command on device
+
+    timeout is specified in seconds, and if no timeout is given, 
+    we will run until the script returns
+    returns:
+    success: Return code from command
+    failure: None
+    """
+
+  @abstractmethod
+  def pushFile(self, localname, destname):
+    """
+    external function
+    returns:
+    success: True
+    failure: False
+    """
+
+  @abstractmethod
+  def mkDir(self, name):
+    """
+    external function
+    returns:
+    success: directory name
+    failure: None
+    """
+
+  def mkDirs(self, filename):
+    """
+    make directory structure on the device
+    WARNING: does not create last part of the path
+    external function
+    returns:
+    success: directory structure that we created
+    failure: None
+    """
+    parts = filename.split('/')
+    name = ""
+    for part in parts:
+        if (part == parts[-1]): break
+        if (part != ""):
+            name += '/' + part
+            if (not self.dirExists(name)):
+                if (self.mkDir(name) == None):
+                    print "failed making directory: " + str(name)
+                    return None
+    return name
+
+  @abstractmethod
+  def pushDir(self, localDir, remoteDir):
+    """
+    push localDir from host to remoteDir on the device
+    external function
+    returns:
+    success: remoteDir
+    failure: None
+    """
+
+  @abstractmethod
+  def dirExists(self, dirname):
+    """
+    external function
+    returns:
+    success: True
+    failure: False
+    """
+
+  @abstractmethod
+  def fileExists(self, filepath):
+    """
+    Because we always have / style paths we make this a lot easier with some
+    assumptions
+    external function
+    returns:
+    success: True
+    failure: False
+    """
+
+  @abstractmethod
+  def listFiles(self, rootdir):
+    """
+    list files on the device, requires cd to directory first
+    external function
+    returns:
+    success: array of filenames, ['file1', 'file2', ...]
+    failure: None
+    """
+
+  @abstractmethod
+  def removeFile(self, filename):
+    """
+    external function
+    returns:
+    success: output of telnet, i.e. "removing file: /mnt/sdcard/tests/test.txt"
+    failure: None
+    """
+
+  @abstractmethod
+  def removeDir(self, remoteDir):
+    """
+    does a recursive delete of directory on the device: rm -Rf remoteDir
+    external function
+    returns:
+    success: output of telnet, i.e. "removing file: /mnt/sdcard/tests/test.txt"
+    failure: None
+    """
+
+  @abstractmethod
+  def getProcessList(self):
+    """
+    external function
+    returns:
+    success: array of process tuples
+    failure: None
+    """
+
+  @abstractmethod
+  def fireProcess(self, appname, failIfRunning=False):
+    """
+    external function
+    DEPRECATED: Use shell() or launchApplication() for new code
+    returns:
+    success: pid
+    failure: None
+    """
+
+  @abstractmethod
+  def launchProcess(self, cmd, outputFile = "process.txt", cwd = '', env = '', failIfRunning=False):
+    """
+    external function
+    DEPRECATED: Use shell() or launchApplication() for new code
+    returns:
+    success: output filename
+    failure: None
+    """
+
+  def processExist(self, appname):
+    """
+    iterates process list and returns pid if exists, otherwise None
+    external function
+    returns:
+    success: pid
+    failure: None
+    """
+
+    pid = None
+
+    #filter out extra spaces
+    parts = filter(lambda x: x != '', appname.split(' '))
+    appname = ' '.join(parts)
+
+    #filter out the quoted env string if it exists
+    #ex: '"name=value;name2=value2;etc=..." process args' -> 'process args'
+    parts = appname.split('"')
+    if (len(parts) > 2):
+      appname = ' '.join(parts[2:]).strip()
+
+    pieces = appname.split(' ')
+    parts = pieces[0].split('/')
+    app = parts[-1]
+
+    procList = self.getProcessList()
+    if (procList == []):
+      return None
+
+    for proc in procList:
+      procName = proc[1].split('/')[-1]
+      if (procName == app):
+        pid = proc[0]
+        break
+    return pid
+
+
+  @abstractmethod
+  def killProcess(self, appname, forceKill=False):
+    """
+    external function
+    returns:
+    success: True
+    failure: False
+    """
+
+  @abstractmethod
+  def catFile(self, remoteFile):
+    """
+    external function
+    returns:
+    success: filecontents
+    failure: None
+    """
+
+  @abstractmethod
+  def pullFile(self, remoteFile):
+    """
+    external function
+    returns:
+    success: output of pullfile, string
+    failure: None
+    """
+
+  @abstractmethod
+  def getFile(self, remoteFile, localFile = ''):
+    """
+    copy file from device (remoteFile) to host (localFile)
+    external function
+    returns:
+    success: output of pullfile, string
+    failure: None
+    """
+
+  @abstractmethod
+  def getDirectory(self, remoteDir, localDir, checkDir=True):
+    """
+    copy directory structure from device (remoteDir) to host (localDir)
+    external function
+    checkDir exists so that we don't create local directories if the
+    remote directory doesn't exist but also so that we don't call isDir
+    twice when recursing.
+    returns:
+    success: list of files, string
+    failure: None
+    """
+
+  @abstractmethod
+  def isDir(self, remotePath):
+    """
+    external function
+    returns:
+    success: True
+    failure: False
+    Throws a FileError exception when null (invalid dir/filename)
+    """
+
+  @abstractmethod
+  def validateFile(self, remoteFile, localFile):
+    """
+    true/false check if the two files have the same md5 sum
+    external function
+    returns:
+    success: True
+    failure: False
+    """
+
+  @abstractmethod
+  def getRemoteHash(self, filename):
+    """
+    return the md5 sum of a remote file
+    internal function
+    returns:
+    success: MD5 hash for given filename
+    failure: None
+    """
+
+  def getLocalHash(self, filename):
+    """
+    return the md5 sum of a file on the host
+    internal function
+    returns:
+    success: MD5 hash for given filename
+    failure: None
+    """
+
+    file = open(filename, 'rb')
+    if (file == None):
+      return None
+
+    try:
+      mdsum = hashlib.md5()
+    except:
+      return None
+
+    while 1:
+      data = file.read(1024)
+      if not data:
+        break
+      mdsum.update(data)
+
+    file.close()
+    hexval = mdsum.hexdigest()
+    if (self.debug >= 3): print "local hash returned: '" + hexval + "'"
+    return hexval
+
+  @abstractmethod
+  def getDeviceRoot(self):
+    """
+    Gets the device root for the testing area on the device
+    For all devices we will use / type slashes and depend on the device-agent
+    to sort those out.  The agent will return us the device location where we
+    should store things, we will then create our /tests structure relative to
+    that returned path.
+    Structure on the device is as follows:
+    /tests
+          /<fennec>|<firefox>  --> approot
+          /profile
+          /xpcshell
+          /reftest
+          /mochitest
+    external
+    returns:
+    success: path for device root
+    failure: None
+    """
+
+  @abstractmethod
+  def getAppRoot(self):
+    """
+    Either we will have /tests/fennec or /tests/firefox but we will never have
+    both.  Return the one that exists
+    TODO: ensure we can support org.mozilla.firefox
+    external function
+    returns:
+    success: path for app root
+    failure: None
+    """
+
+  def getTestRoot(self, type):
+    """
+    Gets the directory location on the device for a specific test type
+    Type is one of: xpcshell|reftest|mochitest
+    external function
+    returns:
+    success: path for test root
+    failure: None
+    """
+
+    devroot = self.getDeviceRoot()
+    if (devroot == None):
+      return None
+
+    if (re.search('xpcshell', type, re.I)):
+      self.testRoot = devroot + '/xpcshell'
+    elif (re.search('?(i)reftest', type)):
+      self.testRoot = devroot + '/reftest'
+    elif (re.search('?(i)mochitest', type)):
+      self.testRoot = devroot + '/mochitest'
+    return self.testRoot
+
+  def signal(self, processID, signalType, signalAction):
+    """
+    Sends a specific process ID a signal code and action.
+    For Example: SIGINT and SIGDFL to process x
+    """
+    #currently not implemented in device agent - todo
+
+    pass
+
+  def getReturnCode(self, processID):
+    """Get a return code from process ending -- needs support on device-agent"""
+    # TODO: make this real
+
+    return 0
+
+  @abstractmethod
+  def unpackFile(self, file_path, dest_dir=None):
+    """
+    external function
+    returns:
+    success: output of unzip command
+    failure: None
+    """
+
+  @abstractmethod
+  def reboot(self, ipAddr=None, port=30000):
+    """
+    external function
+    returns:
+    success: status from test agent
+    failure: None
+    """
+
+  def validateDir(self, localDir, remoteDir):
+    """
+    validate localDir from host to remoteDir on the device
+    external function
+    returns:
+    success: True
+    failure: False
+    """
+
+    if (self.debug >= 2): print "validating directory: " + localDir + " to " + remoteDir
+    for root, dirs, files in os.walk(localDir):
+      parts = root.split(localDir)
+      for file in files:
+        remoteRoot = remoteDir + '/' + parts[1]
+        remoteRoot = remoteRoot.replace('/', '/')
+        if (parts[1] == ""): remoteRoot = remoteDir
+        remoteName = remoteRoot + '/' + file
+        if (self.validateFile(remoteName, os.path.join(root, file)) <> True):
+            return False
+    return True
+
+  @abstractmethod
+  def getInfo(self, directive=None):
+    """
+    Returns information about the device:
+    Directive indicates the information you want to get, your choices are:
+    os - name of the os
+    id - unique id of the device
+    uptime - uptime of the device
+    uptimemillis - uptime of the device in milliseconds (NOT supported on all
+                   implementations)
+    systime - system time of the device
+    screen - screen resolution
+    memory - memory stats
+    process - list of running processes (same as ps)
+    disk - total, free, available bytes on disk
+    power - power status (charge, battery temp)
+    all - all of them - or call it with no parameters to get all the information
+    returns:
+    success: dict of info strings by directive name
+    failure: None
+    """
+
+  @abstractmethod
+  def installApp(self, appBundlePath, destPath=None):
+    """
+    external function
+    returns:
+    success: output from agent for inst command
+    failure: None
+    """
+
+  @abstractmethod
+  def uninstallAppAndReboot(self, appName, installPath=None):
+    """
+    external function
+    returns:
+    success: True
+    failure: None
+    """
+
+  @abstractmethod
+  def updateApp(self, appBundlePath, processName=None,
+                destPath=None, ipAddr=None, port=30000):
+    """
+    external function
+    returns:
+    success: text status from command or callback server
+    failure: None
+    """
+
+  @abstractmethod
+  def getCurrentTime(self):
+    """
+    external function
+    returns:
+    success: time in ms
+    failure: None
+    """
+
+  def recordLogcat(self):
+    """
+    external function
+    returns:
+    success: file is created in <testroot>/logcat.log
+    failure:
+    """
+    #TODO: spawn this off in a separate thread/process so we can collect all the logcat information
+
+    # Right now this is just clearing the logcat so we can only see what happens after this call.
+    buf = StringIO.StringIO()
+    self.shell(['/system/bin/logcat', '-c'], buf, root=True)
+
+  def getLogcat(self):
+    """
+    external function
+    returns: data from the local file
+    success: file is in 'filename'
+    failure: None
+    """
+    buf = StringIO.StringIO()
+    if self.shell(["/system/bin/logcat", "-d", "dalvikvm:S", "ConnectivityService:S", "WifiMonitor:S", "WifiStateTracker:S", "wpa_supplicant:S", "NetworkStateTracker:S"], buf, root=True) != 0:
+      return None
+
+    return str(buf.getvalue()[0:-1]).rstrip().split('\r')
+
+  @abstractmethod
+  def chmodDir(self, remoteDir):
+    """
+    external function
+    returns:
+    success: True
+    failure: False
+    """
+
+  @staticmethod
+  def _escapedCommandLine(cmd):
+    """ Utility function to return escaped and quoted version of command line """
+    quotedCmd = []
+
+    for arg in cmd:
+      arg.replace('&', '\&')
+
+      needsQuoting = False
+      for char in [ ' ', '(', ')', '"', '&' ]:
+        if arg.find(char) >= 0:
+          needsQuoting = True
+          break
+      if needsQuoting:
+        arg = '\'%s\'' % arg
+
+      quotedCmd.append(arg)
+
+    return " ".join(quotedCmd)
+
+
+class NetworkTools:
+  def __init__(self):
+    pass
+
+  # Utilities to get the local ip address
+  def getInterfaceIp(self, ifname):
+    if os.name != "nt":
+      import fcntl
+      import struct
+      s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
+      return socket.inet_ntoa(fcntl.ioctl(
+                              s.fileno(),
+                              0x8915,  # SIOCGIFADDR
+                              struct.pack('256s', ifname[:15])
+                              )[20:24])
+    else:
+      return None
+
+  def getLanIp(self):
+    try:
+      ip = socket.gethostbyname(socket.gethostname())
+    except socket.gaierror:
+      ip = socket.gethostbyname(socket.gethostname() + ".local") # for Mac OS X
+    if ip.startswith("127.") and os.name != "nt":
+      interfaces = ["eth0","eth1","eth2","wlan0","wlan1","wifi0","ath0","ath1","ppp0"]
+      for ifname in interfaces:
+        try:
+          ip = self.getInterfaceIp(ifname)
+          break;
+        except IOError:
+          pass
+    return ip
+
+  # Gets an open port starting with the seed by incrementing by 1 each time
+  def findOpenPort(self, ip, seed):
+    try:
+      s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+      s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
+      connected = False
+      if isinstance(seed, basestring):
+        seed = int(seed)
+      maxportnum = seed + 5000 # We will try at most 5000 ports to find an open one
+      while not connected:
+        try:
+          s.bind((ip, seed))
+          connected = True
+          s.close()
+          break
+        except:
+          if seed > maxportnum:
+            print "Could not find open port after checking 5000 ports"
+          raise
+        seed += 1
+    except:
+      print "Socket error trying to find open port"
+
+    return seed
+
+def _pop_last_line(file):
+  '''
+  Utility function to get the last line from a file (shared between ADB and
+  SUT device managers). Function also removes it from the file. Intended to
+  strip off the return code from a shell command.
+  '''
+  bytes_from_end = 1
+  file.seek(0, 2)
+  length = file.tell() + 1
+  while bytes_from_end < length:
+    file.seek((-1)*bytes_from_end, 2)
+    data = file.read()
+
+    if bytes_from_end == length-1 and len(data) == 0: # no data, return None
+      return None
+
+    if data[0] == '\n' or bytes_from_end == length-1:
+      # found the last line, which should have the return value
+      if data[0] == '\n':
+        data = data[1:]
+
+      # truncate off the return code line
+      file.truncate(length - bytes_from_end)
+      file.seek(0,2)
+      file.write('\0')
+
+      return data
+
+    bytes_from_end += 1
+
+  return None
new file mode 100644
--- /dev/null
+++ b/testing/mozbase/mozdevice/mozdevice/devicemanagerADB.py
@@ -0,0 +1,900 @@
+# 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/.
+
+import subprocess
+from devicemanager import DeviceManager, DMError, _pop_last_line
+import re
+import os
+import tempfile
+import time
+
+class DeviceManagerADB(DeviceManager):
+
+  def __init__(self, host=None, port=20701, retrylimit=5, packageName='fennec',
+               adbPath='adb', deviceSerial=None, deviceRoot=None):
+    self.host = host
+    self.port = port
+    self.retrylimit = retrylimit
+    self.retries = 0
+    self._sock = None
+    self.useRunAs = False
+    self.haveRoot = False
+    self.useDDCopy = False
+    self.useZip = False
+    self.packageName = None
+    self.tempDir = None
+    self.deviceRoot = deviceRoot
+
+    # the path to adb, or 'adb' to assume that it's on the PATH
+    self.adbPath = adbPath
+
+    # The serial number of the device to use with adb, used in cases
+    # where multiple devices are being managed by the same adb instance.
+    self.deviceSerial = deviceSerial
+
+    if packageName == 'fennec':
+      if os.getenv('USER'):
+        self.packageName = 'org.mozilla.fennec_' + os.getenv('USER')
+      else:
+        self.packageName = 'org.mozilla.fennec_'
+    elif packageName:
+      self.packageName = packageName
+
+    # verify that we can run the adb command. can't continue otherwise
+    self.verifyADB()
+
+    # try to connect to the device over tcp/ip if we have a hostname
+    if self.host:
+      self.connectRemoteADB()
+
+    # verify that we can connect to the device. can't continue
+    self.verifyDevice()
+
+    # set up device root
+    self.setupDeviceRoot()
+
+    # Can we use run-as? (currently not required)
+    try:
+      self.verifyRunAs()
+    except DMError:
+      pass
+
+    # Can we run things as root? (currently not required)
+    useRunAsTmp = self.useRunAs
+    self.useRunAs = False
+    try:
+      self.verifyRoot()
+    except DMError:
+      try:
+        self.checkCmd(["root"])
+        # The root command does not fail even if ADB cannot get
+        # root rights (e.g. due to production builds), so we have
+        # to check again ourselves that we have root now.
+        self.verifyRoot()
+      except DMError:
+        if useRunAsTmp:
+          print "restarting as root failed, but run-as available"
+        else:
+          print "restarting as root failed"
+    self.useRunAs = useRunAsTmp
+
+    # can we use zip to speed up some file operations? (currently not
+    # required)
+    try:
+      self.verifyZip()
+    except DMError:
+      pass
+
+  def __del__(self):
+    if self.host:
+      self.disconnectRemoteADB()
+
+  # external function: executes shell command on device.
+  # timeout is specified in seconds, and if no timeout is given, 
+  # we will run until the script returns
+  # returns:
+  # success: <return code>
+  # failure: None
+  def shell(self, cmd, outputfile, env=None, cwd=None, timeout=None, root=False):
+    # FIXME: this function buffers all output of the command into memory,
+    # always. :(
+
+    # Getting the return code is more complex than you'd think because adb
+    # doesn't actually return the return code from a process, so we have to
+    # capture the output to get it
+    if root:
+      cmdline = "su -c \"%s\"" % self._escapedCommandLine(cmd)
+    else:
+      cmdline = self._escapedCommandLine(cmd)
+    cmdline += "; echo $?"
+
+    # prepend cwd and env to command if necessary
+    if cwd:
+      cmdline = "cd %s; %s" % (cwd, cmdline)
+    if env:
+      envstr = '; '.join(map(lambda x: 'export %s=%s' % (x[0], x[1]), env.iteritems()))
+      cmdline = envstr + "; " + cmdline
+
+    # all output should be in stdout
+    args=[self.adbPath]
+    if self.deviceSerial:
+        args.extend(['-s', self.deviceSerial])
+    args.extend(["shell", cmdline])
+    proc = subprocess.Popen(args,
+                            stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+    if timeout:
+        timeout = int(timeout)
+        start_time = time.time()
+        ret_code = proc.poll()
+        while ((time.time() - start_time) <= timeout) and ret_code == None:
+            time.sleep(1)
+            ret_code = proc.poll()
+        if ret_code == None:
+            proc.kill()
+            raise DMError("Timeout exceeded for shell call")
+    (stdout, stderr) = proc.communicate()
+    outputfile.write(stdout.rstrip('\n'))
+
+    lastline = _pop_last_line(outputfile)
+    if lastline:
+      m = re.search('([0-9]+)', lastline)
+      if m:
+        return_code = m.group(1)
+        outputfile.seek(-2, 2)
+        outputfile.truncate() # truncate off the return code
+        return int(return_code)
+
+    return None
+
+  def connectRemoteADB(self):
+    self.checkCmd(["connect", self.host + ":" + str(self.port)])
+
+  def disconnectRemoteADB(self):
+    self.checkCmd(["disconnect", self.host + ":" + str(self.port)])
+
+  # external function
+  # returns:
+  #  success: True
+  #  failure: False
+  def pushFile(self, localname, destname):
+    try:
+      if (os.name == "nt"):
+        destname = destname.replace('\\', '/')
+      if (self.useRunAs):
+        remoteTmpFile = self.getTempDir() + "/" + os.path.basename(localname)
+        self.checkCmd(["push", os.path.realpath(localname), remoteTmpFile])
+        if self.useDDCopy:
+          self.checkCmdAs(["shell", "dd", "if=" + remoteTmpFile, "of=" + destname])
+        else:
+          self.checkCmdAs(["shell", "cp", remoteTmpFile, destname])
+        self.checkCmd(["shell", "rm", remoteTmpFile])
+      else:
+        self.checkCmd(["push", os.path.realpath(localname), destname])
+      if (self.isDir(destname)):
+        destname = destname + "/" + os.path.basename(localname)
+      return True
+    except:
+      return False
+
+  # external function
+  # returns:
+  #  success: directory name
+  #  failure: None
+  def mkDir(self, name):
+    try:
+      result = self.runCmdAs(["shell", "mkdir", name]).stdout.read()
+      if 'read-only file system' in result.lower():
+        return None
+      if 'file exists' in result.lower():
+        return name
+      return name
+    except:
+      return None
+
+  # push localDir from host to remoteDir on the device
+  # external function
+  # returns:
+  #  success: remoteDir
+  #  failure: None
+  def pushDir(self, localDir, remoteDir):
+    # adb "push" accepts a directory as an argument, but if the directory
+    # contains symbolic links, the links are pushed, rather than the linked
+    # files; we either zip/unzip or push file-by-file to get around this 
+    # limitation
+    try:
+      if (not self.dirExists(remoteDir)):
+        self.mkDirs(remoteDir+"/x")
+      if (self.useZip):
+        try:
+          localZip = tempfile.mktemp()+".zip"
+          remoteZip = remoteDir + "/adbdmtmp.zip"
+          subprocess.check_output(["zip", "-r", localZip, '.'], cwd=localDir)
+          self.pushFile(localZip, remoteZip)
+          os.remove(localZip)
+          data = self.runCmdAs(["shell", "unzip", "-o", remoteZip, "-d", remoteDir]).stdout.read()
+          self.checkCmdAs(["shell", "rm", remoteZip])
+          if (re.search("unzip: exiting", data) or re.search("Operation not permitted", data)):
+            raise Exception("unzip failed, or permissions error")
+        except:
+          print "zip/unzip failure: falling back to normal push"
+          self.useZip = False
+          self.pushDir(localDir, remoteDir)
+      else:
+        for root, dirs, files in os.walk(localDir, followlinks=True):
+          relRoot = os.path.relpath(root, localDir)
+          for file in files:
+            localFile = os.path.join(root, file)
+            remoteFile = remoteDir + "/"
+            if (relRoot!="."):
+              remoteFile = remoteFile + relRoot + "/"
+            remoteFile = remoteFile + file
+            self.pushFile(localFile, remoteFile)
+          for dir in dirs:
+            targetDir = remoteDir + "/"
+            if (relRoot!="."):
+              targetDir = targetDir + relRoot + "/"
+            targetDir = targetDir + dir
+            if (not self.dirExists(targetDir)):
+              self.mkDir(targetDir)
+      return remoteDir
+    except:
+      print "pushing " + localDir + " to " + remoteDir + " failed"
+      return None
+
+  # external function
+  # returns:
+  #  success: True
+  #  failure: False
+  def dirExists(self, dirname):
+    return self.isDir(dirname)
+
+  # Because we always have / style paths we make this a lot easier with some
+  # assumptions
+  # external function
+  # returns:
+  #  success: True
+  #  failure: False
+  def fileExists(self, filepath):
+    p = self.runCmd(["shell", "ls", "-a", filepath])
+    data = p.stdout.readlines()
+    if (len(data) == 1):
+      if (data[0].rstrip() == filepath):
+        return True
+    return False
+
+  def removeFile(self, filename):
+    return self.runCmd(["shell", "rm", filename]).stdout.read()
+
+  # does a recursive delete of directory on the device: rm -Rf remoteDir
+  # external function
+  # returns:
+  #  success: output of telnet, i.e. "removing file: /mnt/sdcard/tests/test.txt"
+  #  failure: None
+  def removeSingleDir(self, remoteDir):
+    return self.runCmd(["shell", "rmdir", remoteDir]).stdout.read()
+
+  # does a recursive delete of directory on the device: rm -Rf remoteDir
+  # external function
+  # returns:
+  #  success: output of telnet, i.e. "removing file: /mnt/sdcard/tests/test.txt"
+  #  failure: None
+  def removeDir(self, remoteDir):
+      out = ""
+      if (self.isDir(remoteDir)):
+          files = self.listFiles(remoteDir.strip())
+          for f in files:
+              if (self.isDir(remoteDir.strip() + "/" + f.strip())):
+                  out += self.removeDir(remoteDir.strip() + "/" + f.strip())
+              else:
+                  out += self.removeFile(remoteDir.strip() + "/" + f.strip())
+          out += self.removeSingleDir(remoteDir.strip())
+      else:
+          out += self.removeFile(remoteDir.strip())
+      return out
+
+  def isDir(self, remotePath):
+      p = self.runCmd(["shell", "ls", "-a", remotePath + '/'])
+
+      data = p.stdout.readlines()
+      if len(data) == 1:
+          res = data[0]
+          if "Not a directory" in res or "No such file or directory" in res:
+              return False
+
+      return True
+
+  def listFiles(self, rootdir):
+      p = self.runCmd(["shell", "ls", "-a", rootdir])
+      data = p.stdout.readlines()
+      data[:] = [item.rstrip('\r\n') for item in data]
+      if (len(data) == 1):
+          if (data[0] == rootdir):
+              return []
+          if (data[0].find("No such file or directory") != -1):
+              return []
+          if (data[0].find("Not a directory") != -1):
+              return []
+          if (data[0].find("Permission denied") != -1):
+              return []
+          if (data[0].find("opendir failed") != -1):
+              return []
+      return data
+
+  # external function
+  # returns:
+  #  success: array of process tuples
+  #  failure: []
+  def getProcessList(self):
+    p = self.runCmd(["shell", "ps"])
+      # first line is the headers
+    p.stdout.readline()
+    proc = p.stdout.readline()
+    ret = []
+    while (proc):
+      els = proc.split()
+      ret.append(list([els[1], els[len(els) - 1], els[0]]))
+      proc =  p.stdout.readline()
+    return ret
+
+  # external function
+  # DEPRECATED: Use shell() or launchApplication() for new code
+  # returns:
+  #  success: pid
+  #  failure: None
+  def fireProcess(self, appname, failIfRunning=False):
+    #strip out env vars
+    parts = appname.split('"');
+    if (len(parts) > 2):
+      parts = parts[2:]
+    return self.launchProcess(parts, failIfRunning)
+
+  # external function
+  # DEPRECATED: Use shell() or launchApplication() for new code
+  # returns:
+  #  success: output filename
+  #  failure: None
+  def launchProcess(self, cmd, outputFile = "process.txt", cwd = '', env = '', failIfRunning=False):
+    if cmd[0] == "am":
+      self.checkCmd(["shell"] + cmd)
+      return outputFile
+
+    acmd = ["shell", "am", "start", "-W"]
+    cmd = ' '.join(cmd).strip()
+    i = cmd.find(" ")
+    # SUT identifies the URL by looking for :\\ -- another strategy to consider
+    re_url = re.compile('^[http|file|chrome|about].*')
+    last = cmd.rfind(" ")
+    uri = ""
+    args = ""
+    if re_url.match(cmd[last:].strip()):
+      args = cmd[i:last].strip()
+      uri = cmd[last:].strip()
+    else:
+      args = cmd[i:].strip()
+    acmd.append("-n")
+    acmd.append(cmd[0:i] + "/.App")
+    if args != "":
+      acmd.append("--es")
+      acmd.append("args")
+      acmd.append(args)
+    if env != '' and env != None:
+      envCnt = 0
+      # env is expected to be a dict of environment variables
+      for envkey, envval in env.iteritems():
+        acmd.append("--es")
+        acmd.append("env" + str(envCnt))
+        acmd.append(envkey + "=" + envval);
+        envCnt += 1
+    if uri != "":
+      acmd.append("-d")
+      acmd.append(''.join(['\'',uri, '\'']));
+    print acmd
+    self.checkCmd(acmd)
+    return outputFile
+
+  # external function
+  # returns:
+  #  success: True
+  #  failure: False
+  def killProcess(self, appname, forceKill=False):
+    procs = self.getProcessList()
+    didKillProcess = False
+    for (pid, name, user) in procs:
+      if name == appname:
+         args = ["shell", "kill"]
+         if forceKill:
+           args.append("-9")
+         args.append(pid)
+         p = self.runCmdAs(args)
+         p.communicate()
+         if p.returncode == 0:
+             didKillProcess = True
+
+    return didKillProcess
+
+  # external function
+  # returns:
+  #  success: filecontents
+  #  failure: None
+  def catFile(self, remoteFile):
+    #p = self.runCmd(["shell", "cat", remoteFile])
+    #return p.stdout.read()
+    return self.getFile(remoteFile)
+
+  # external function
+  # returns:
+  #  success: output of pullfile, string
+  #  failure: None
+  def pullFile(self, remoteFile):
+    #return self.catFile(remoteFile)
+    return self.getFile(remoteFile)
+
+  # copy file from device (remoteFile) to host (localFile)
+  # external function
+  # returns:
+  #  success: output of pullfile, string
+  #  failure: None
+  def getFile(self, remoteFile, localFile = 'tmpfile_dm_adb'):
+    # TODO: add debug flags and allow for printing stdout
+    # self.runCmd(["pull", remoteFile, localFile])
+    try:
+
+      # First attempt to pull file regularly
+      outerr = self.runCmd(["pull",  remoteFile, localFile]).communicate()
+
+      # Now check stderr for errors
+      if outerr[1]:
+        errl = outerr[1].splitlines()
+        if (len(errl) == 1):
+          if (((errl[0].find("Permission denied") != -1)
+            or (errl[0].find("does not exist") != -1))
+            and self.useRunAs):
+            # If we lack permissions to read but have run-as, then we should try
+            # to copy the file to a world-readable location first before attempting
+            # to pull it again.
+            remoteTmpFile = self.getTempDir() + "/" + os.path.basename(remoteFile)
+            self.checkCmdAs(["shell", "dd", "if=" + remoteFile, "of=" + remoteTmpFile])
+            self.checkCmdAs(["shell", "chmod", "777", remoteTmpFile])
+            self.runCmd(["pull",  remoteTmpFile, localFile]).stdout.read()
+            # Clean up temporary file
+            self.checkCmdAs(["shell", "rm", remoteTmpFile])
+
+      f = open(localFile)
+      ret = f.read()
+      f.close()
+      return ret
+    except:
+      return None
+
+  # copy directory structure from device (remoteDir) to host (localDir)
+  # external function
+  # checkDir exists so that we don't create local directories if the
+  # remote directory doesn't exist but also so that we don't call isDir
+  # twice when recursing.
+  # returns:
+  #  success: list of files, string
+  #  failure: None
+  def getDirectory(self, remoteDir, localDir, checkDir=True):
+    ret = []
+    p = self.runCmd(["pull", remoteDir, localDir])
+    p.stdout.readline()
+    line = p.stdout.readline()
+    while (line):
+      els = line.split()
+      f = els[len(els) - 1]
+      i = f.find(localDir)
+      if (i != -1):
+        if (localDir[len(localDir) - 1] != '/'):
+          i = i + 1
+        f = f[i + len(localDir):]
+      i = f.find("/")
+      if (i > 0):
+        f = f[0:i]
+      ret.append(f)
+      line =  p.stdout.readline()
+    #the last line is a summary
+    if (len(ret) > 0):
+      ret.pop()
+    return ret
+
+
+
+  # true/false check if the two files have the same md5 sum
+  # external function
+  # returns:
+  #  success: True
+  #  failure: False
+  def validateFile(self, remoteFile, localFile):
+    return self.getRemoteHash(remoteFile) == self.getLocalHash(localFile)
+
+  # return the md5 sum of a remote file
+  # internal function
+  # returns:
+  #  success: MD5 hash for given filename
+  #  failure: None
+  def getRemoteHash(self, filename):
+    data = self.runCmd(["shell", "ls", "-l", filename]).stdout.read()
+    return data.split()[3]
+
+  def getLocalHash(self, filename):
+    data = subprocess.Popen(["ls", "-l", filename], stdout=subprocess.PIPE).stdout.read()
+    return data.split()[4]
+
+  # Internal method to setup the device root and cache its value
+  def setupDeviceRoot(self):
+    # if self.deviceRoot is already set, create it if necessary, and use it
+    if self.deviceRoot:
+      if not self.dirExists(self.deviceRoot):
+        if not self.mkDir(self.deviceRoot):
+          raise DMError("Unable to create device root %s" % self.deviceRoot)
+      return
+
+    # /mnt/sdcard/tests is preferred to /data/local/tests, but this can be
+    # over-ridden by creating /data/local/tests
+    testRoot = "/data/local/tests"
+    if (self.dirExists(testRoot)):
+      self.deviceRoot = testRoot
+      return
+
+    for (basePath, subPath) in [('/mnt/sdcard', 'tests'),
+                                ('/data/local', 'tests')]:
+      if self.dirExists(basePath):
+        testRoot = os.path.join(basePath, subPath)
+        if self.mkDir(testRoot):
+          self.deviceRoot = testRoot
+          return
+
+    raise DMError("Unable to set up device root as /mnt/sdcard/tests "
+                  "or /data/local/tests")
+
+  # Gets the device root for the testing area on the device
+  # For all devices we will use / type slashes and depend on the device-agent
+  # to sort those out.  The agent will return us the device location where we
+  # should store things, we will then create our /tests structure relative to
+  # that returned path.
+  # Structure on the device is as follows:
+  # /tests
+  #       /<fennec>|<firefox>  --> approot
+  #       /profile
+  #       /xpcshell
+  #       /reftest
+  #       /mochitest
+  #
+  # external function
+  # returns:
+  #  success: path for device root
+  #  failure: None
+  def getDeviceRoot(self):
+    return self.deviceRoot
+
+  # Gets the temporary directory we are using on this device
+  # base on our device root, ensuring also that it exists.
+  #
+  # internal function
+  # returns:
+  #  success: path for temporary directory
+  #  failure: None
+  def getTempDir(self):
+    # Cache result to speed up operations depending
+    # on the temporary directory.
+    if self.tempDir == None:
+      self.tempDir = self.getDeviceRoot() + "/tmp"
+      if (not self.dirExists(self.tempDir)):
+        return self.mkDir(self.tempDir)
+
+    return self.tempDir
+
+  # Either we will have /tests/fennec or /tests/firefox but we will never have
+  # both.  Return the one that exists
+  # TODO: ensure we can support org.mozilla.firefox
+  # external function
+  # returns:
+  #  success: path for app root
+  #  failure: None
+  def getAppRoot(self, packageName):
+    devroot = self.getDeviceRoot()
+    if (devroot == None):
+      return None
+
+    if (packageName and self.dirExists('/data/data/' + packageName)):
+      self.packageName = packageName
+      return '/data/data/' + packageName
+    elif (self.packageName and self.dirExists('/data/data/' + self.packageName)):
+      return '/data/data/' + self.packageName
+
+    # Failure (either not installed or not a recognized platform)
+    print "devicemanagerADB: getAppRoot failed"
+    return None
+
+  # Gets the directory location on the device for a specific test type
+  # Type is one of: xpcshell|reftest|mochitest
+  # external function
+  # returns:
+  #  success: path for test root
+  #  failure: None
+  def getTestRoot(self, type):
+    devroot = self.getDeviceRoot()
+    if (devroot == None):
+      return None
+
+    if (re.search('xpcshell', type, re.I)):
+      self.testRoot = devroot + '/xpcshell'
+    elif (re.search('?(i)reftest', type)):
+      self.testRoot = devroot + '/reftest'
+    elif (re.search('?(i)mochitest', type)):
+      self.testRoot = devroot + '/mochitest'
+    return self.testRoot
+
+
+  # external function
+  # returns:
+  #  success: status from test agent
+  #  failure: None
+  def reboot(self, wait = False):
+    ret = self.runCmd(["reboot"]).stdout.read()
+    if (not wait):
+      return "Success"
+    countdown = 40
+    while (countdown > 0):
+      countdown
+      try:
+        self.checkCmd(["wait-for-device", "shell", "ls", "/sbin"])
+        return ret
+      except:
+        try:
+          self.checkCmd(["root"])
+        except:
+          time.sleep(1)
+          print "couldn't get root"
+    return "Success"
+
+  # external function
+  # returns:
+  #  success: text status from command or callback server
+  #  failure: None
+  def updateApp(self, appBundlePath, processName=None, destPath=None, ipAddr=None, port=30000):
+    return self.runCmd(["install", "-r", appBundlePath]).stdout.read()
+
+  # external function
+  # returns:
+  #  success: time in ms
+  #  failure: None
+  def getCurrentTime(self):
+    timestr = self.runCmd(["shell", "date", "+%s"]).stdout.read().strip()
+    if (not timestr or not timestr.isdigit()):
+        return None
+    return str(int(timestr)*1000)
+
+  # Returns information about the device:
+  # Directive indicates the information you want to get, your choices are:
+  # os - name of the os
+  # id - unique id of the device
+  # uptime - uptime of the device
+  # systime - system time of the device
+  # screen - screen resolution
+  # memory - memory stats
+  # process - list of running processes (same as ps)
+  # disk - total, free, available bytes on disk
+  # power - power status (charge, battery temp)
+  # all - all of them - or call it with no parameters to get all the information
+  ### Note that uptimemillis is NOT supported, as there is no way to get this
+  ### data from the shell.
+  # returns:
+  #   success: dict of info strings by directive name
+  #   failure: {}
+  def getInfo(self, directive="all"):
+    ret = {}
+    if (directive == "id" or directive == "all"):
+      ret["id"] = self.runCmd(["get-serialno"]).stdout.read()
+    if (directive == "os" or directive == "all"):
+      ret["os"] = self.runCmd(["shell", "getprop", "ro.build.display.id"]).stdout.read()
+    if (directive == "uptime" or directive == "all"):
+      utime = self.runCmd(["shell", "uptime"]).stdout.read()
+      if (not utime):
+        raise DMError("error getting uptime")
+      utime = utime[9:]
+      hours = utime[0:utime.find(":")]
+      utime = utime[utime[1:].find(":") + 2:]
+      minutes = utime[0:utime.find(":")]
+      utime = utime[utime[1:].find(":") +  2:]
+      seconds = utime[0:utime.find(",")]
+      ret["uptime"] = ["0 days " + hours + " hours " + minutes + " minutes " + seconds + " seconds"]
+    if (directive == "process" or directive == "all"):
+      ret["process"] = self.runCmd(["shell", "ps"]).stdout.read()
+    if (directive == "systime" or directive == "all"):
+      ret["systime"] = self.runCmd(["shell", "date"]).stdout.read()
+    print ret
+    return ret
+
+  def runCmd(self, args):
+    # If we are not root but have run-as, and we're trying to execute
+    # a shell command then using run-as is the best we can do
+    finalArgs = [self.adbPath]
+    if self.deviceSerial:
+      finalArgs.extend(['-s', self.deviceSerial])
+    if (not self.haveRoot and self.useRunAs and args[0] == "shell" and args[1] != "run-as"):
+      args.insert(1, "run-as")
+      args.insert(2, self.packageName)
+    finalArgs.extend(args)
+    return subprocess.Popen(finalArgs, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
+
+  def runCmdAs(self, args):
+    if self.useRunAs:
+      args.insert(1, "run-as")
+      args.insert(2, self.packageName)
+    return self.runCmd(args)
+
+  # timeout is specified in seconds, and if no timeout is given, 
+  # we will run until the script returns
+  def checkCmd(self, args, timeout=None):
+    # If we are not root but have run-as, and we're trying to execute
+    # a shell command then using run-as is the best we can do
+    finalArgs = [self.adbPath]
+    if self.deviceSerial:
+      finalArgs.extend(['-s', self.deviceSerial])
+    if (not self.haveRoot and self.useRunAs and args[0] == "shell" and args[1] != "run-as"):
+      args.insert(1, "run-as")
+      args.insert(2, self.packageName)
+    finalArgs.extend(args)
+    if timeout:
+        timeout = int(timeout)
+        proc = subprocess.Popen(finalArgs)
+        start_time = time.time()
+        ret_code = proc.poll()
+        while ((time.time() - start_time) <= timeout) and ret_code == None:
+            time.sleep(1)
+            ret_code = proc.poll()
+        if ret_code == None:
+            proc.kill()
+            raise DMError("Timeout exceeded for checkCmd call")
+        return ret_code
+    return subprocess.check_call(finalArgs)
+
+  def checkCmdAs(self, args, timeout=None):
+    if (self.useRunAs):
+      args.insert(1, "run-as")
+      args.insert(2, self.packageName)
+    return self.checkCmd(args, timeout)
+
+  # external function
+  # returns:
+  #  success: True
+  #  failure: False
+  def chmodDir(self, remoteDir):
+    if (self.isDir(remoteDir)):
+      files = self.listFiles(remoteDir.strip())
+      for f in files:
+        remoteEntry = remoteDir.strip() + "/" + f.strip()
+        if (self.isDir(remoteEntry)):
+          self.chmodDir(remoteEntry)
+        else:
+          self.checkCmdAs(["shell", "chmod", "777", remoteEntry])
+          print "chmod " + remoteEntry
+      self.checkCmdAs(["shell", "chmod", "777", remoteDir])
+      print "chmod " + remoteDir
+    else:
+      self.checkCmdAs(["shell", "chmod", "777", remoteDir.strip()])
+      print "chmod " + remoteDir.strip()
+    return True
+
+  def verifyADB(self):
+    # Check to see if adb itself can be executed.
+    if self.adbPath != 'adb':
+      if not os.access(self.adbPath, os.X_OK):
+        raise DMError("invalid adb path, or adb not executable: %s", self.adbPath)
+
+    try:
+      self.checkCmd(["version"])
+    except os.error, err:
+      raise DMError("unable to execute ADB (%s): ensure Android SDK is installed and adb is in your $PATH" % err)
+    except subprocess.CalledProcessError:
+      raise DMError("unable to execute ADB: ensure Android SDK is installed and adb is in your $PATH")
+
+  def verifyDevice(self):
+    # If there is a device serial number, see if adb is connected to it
+    if self.deviceSerial:
+      deviceStatus = None
+      proc = subprocess.Popen([self.adbPath, "devices"],
+                              stdout=subprocess.PIPE,
+                              stderr=subprocess.STDOUT)
+      for line in proc.stdout:
+        m = re.match('(.+)?\s+(.+)$', line)
+        if m:
+          if self.deviceSerial == m.group(1):
+            deviceStatus = m.group(2)
+      if deviceStatus == None:
+        raise DMError("device not found: %s" % self.deviceSerial)
+      elif deviceStatus != "device":
+        raise DMError("bad status for device %s: %s" % (self.deviceSerial,
+                                                        deviceStatus))
+
+    # Check to see if we can connect to device and run a simple command
+    try:
+      self.checkCmd(["shell", "echo"])
+    except subprocess.CalledProcessError:
+      raise DMError("unable to connect to device: is it plugged in?")
+
+  def verifyRoot(self):
+    # a test to see if we have root privs
+    p = self.runCmd(["shell", "id"])
+    response = p.stdout.readline()
+    response = response.rstrip()
+    response = response.split(' ')
+    if (response[0].find('uid=0') < 0 or response[1].find('gid=0') < 0):
+      print "NOT running as root ", response[0].find('uid=0')
+      raise DMError("not running as root")
+
+    self.haveRoot = True
+
+  def isCpAvailable(self):
+    # Some Android systems may not have a cp command installed,
+    # or it may not be executable by the user.
+    data = self.runCmd(["shell", "cp"]).stdout.read()
+    if (re.search('Usage', data)):
+      return True
+    else:
+      data = self.runCmd(["shell", "dd", "-"]).stdout.read()
+      if (re.search('unknown operand', data)):
+        print "'cp' not found, but 'dd' was found as a replacement"
+        self.useDDCopy = True
+        return True
+      print "unable to execute 'cp' on device; consider installing busybox from Android Market"
+      return False
+
+  def verifyRunAs(self):
+    # If a valid package name is available, and certain other
+    # conditions are met, devicemanagerADB can execute file operations
+    # via the "run-as" command, so that pushed files and directories 
+    # are created by the uid associated with the package, more closely
+    # echoing conditions encountered by Fennec at run time.
+    # Check to see if run-as can be used here, by verifying a 
+    # file copy via run-as.
+    self.useRunAs = False
+    devroot = self.getDeviceRoot()
+    if (self.packageName and self.isCpAvailable() and devroot):
+      tmpDir = self.getTempDir()
+
+      # The problem here is that run-as doesn't cause a non-zero exit code
+      # when failing because of a non-existent or non-debuggable package :(
+      runAsOut = self.runCmd(["shell", "run-as", self.packageName, "mkdir", devroot + "/sanity"]).communicate()[0]
+      if runAsOut.startswith("run-as:") and ("not debuggable" in runAsOut or
+                                             "is unknown" in runAsOut):
+        raise DMError("run-as failed sanity check")
+
+      tmpfile = tempfile.NamedTemporaryFile()
+      self.checkCmd(["push", tmpfile.name, tmpDir + "/tmpfile"])
+      if self.useDDCopy:
+        self.checkCmd(["shell", "run-as", self.packageName, "dd", "if=" + tmpDir + "/tmpfile", "of=" + devroot + "/sanity/tmpfile"])
+      else:
+        self.checkCmd(["shell", "run-as", self.packageName, "cp", tmpDir + "/tmpfile", devroot + "/sanity"])
+      if (self.fileExists(devroot + "/sanity/tmpfile")):
+        print "will execute commands via run-as " + self.packageName
+        self.useRunAs = True
+      self.checkCmd(["shell", "rm", devroot + "/tmp/tmpfile"])
+      self.checkCmd(["shell", "run-as", self.packageName, "rm", "-r", devroot + "/sanity"])
+
+  def isUnzipAvailable(self):
+    data = self.runCmdAs(["shell", "unzip"]).stdout.read()
+    if (re.search('Usage', data)):
+      return True
+    else:
+      return False
+
+  def isLocalZipAvailable(self):
+    try:
+      subprocess.check_call(["zip", "-?"], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+    except:
+      return False
+    return True
+
+  def verifyZip(self):
+    # If "zip" can be run locally, and "unzip" can be run remotely, then pushDir
+    # can use these to push just one file per directory -- a significant
+    # optimization for large directories.
+    self.useZip = False
+    if (self.isUnzipAvailable() and self.isLocalZipAvailable()):
+      print "will use zip to push directories"
+      self.useZip = True
+    else:
+      raise DMEr