Bug 1021756 - Allow to run adbd as root. r=wlach
authorArmen Zambrano Gasparnian <armenzg@mozilla.com>
Tue, 05 Aug 2014 11:58:30 -0400
changeset 197976 0dff8ac3f629f6f061aa78eb5ed06e60d5748359
parent 197975 1cb5bd26726ea0c980730d1d29509446f69c7208
child 197977 8ecb3e5d5013a34c87587bb44260d9014ead2dba
push id27256
push userkwierso@gmail.com
push dateWed, 06 Aug 2014 00:06:20 +0000
treeherdermozilla-central@6cbdd4d523a7 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerswlach
bugs1021756
milestone34.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1021756 - Allow to run adbd as root. r=wlach This allows a device that starts adbd as non-root to restart adbd every time that is needed to ensure the ability of running privileged tasks on the device.
testing/mozbase/mozdevice/adb_tests/test_device_running_adb_as_root.py
testing/mozbase/mozdevice/mozdevice/devicemanagerADB.py
new file mode 100644
--- /dev/null
+++ b/testing/mozbase/mozdevice/adb_tests/test_device_running_adb_as_root.py
@@ -0,0 +1,46 @@
+"""
+ This test is to test devices that adbd does not get started as root.
+ Specifically devices that have ro.secure == 1 and ro.debuggable == 1
+
+ Running this test case requires various reboots which makes it a
+ very slow test case to run.
+"""
+import unittest
+import sys
+
+from mozdevice import DeviceManagerADB
+
+class TestFileOperations(unittest.TestCase):
+    def setUp(self):
+        dm = DeviceManagerADB()
+        dm.reboot(wait=True)
+
+    def test_run_adb_as_root_parameter(self):
+        dm = DeviceManagerADB()
+        self.assertTrue(dm.processInfo("adbd")[2] != "root")
+        dm = DeviceManagerADB(runAdbAsRoot=True)
+        self.assertTrue(dm.processInfo("adbd")[2] == "root")
+
+    def test_after_reboot_adb_runs_as_root(self):
+        dm = DeviceManagerADB(runAdbAsRoot=True)
+        self.assertTrue(dm.processInfo("adbd")[2] == "root")
+        dm.reboot(wait=True)
+        self.assertTrue(dm.processInfo("adbd")[2] == "root")
+
+    def tearDown(self):
+        dm = DeviceManagerADB()
+        dm.reboot()
+
+if __name__ == "__main__":
+    dm = DeviceManagerADB()
+    if not dm.devices():
+       print "There are no connected adb devices"
+       sys.exit(1)
+    else:
+        if not (int(dm._runCmd(["shell", "getprop", "ro.secure"]).output[0]) and \
+                int(dm._runCmd(["shell", "getprop", "ro.debuggable"]).output[0])):
+            print "This test case is meant for devices with devices that start " \
+                    "adbd as non-root and allows for adbd to be restarted as root."
+            sys.exit(1)
+
+    unittest.main()
--- a/testing/mozbase/mozdevice/mozdevice/devicemanagerADB.py
+++ b/testing/mozbase/mozdevice/mozdevice/devicemanagerADB.py
@@ -29,30 +29,34 @@ class DeviceManagerADB(DeviceManager):
     _pollingInterval = 0.01
     _packageName = None
     _tempDir = None
     connected = False
     default_timeout = 300
 
     def __init__(self, host=None, port=5555, retryLimit=5, packageName='fennec',
                  adbPath='adb', deviceSerial=None, deviceRoot=None,
-                 logLevel=mozlog.ERROR, autoconnect=True, **kwargs):
+                 logLevel=mozlog.ERROR, autoconnect=True, runAdbAsRoot=False, **kwargs):
         DeviceManager.__init__(self, logLevel=logLevel,
                                deviceRoot=deviceRoot)
         self.host = host
         self.port = port
         self.retryLimit = retryLimit
 
         # 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
 
+        # Some devices do no start adb as root, if allowed you can use
+        # this to reboot adbd on the device as root automatically
+        self._runAdbAsRoot = runAdbAsRoot
+
         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
 
@@ -467,17 +471,20 @@ class DeviceManagerADB(DeviceManager):
             self._tempDir = "%s/tmp" % self.deviceRoot
             self.mkDir(self._tempDir)
 
         return self._tempDir
 
     def reboot(self, wait = False, **kwargs):
         self._checkCmd(["reboot"])
         if wait:
-            self._checkCmd(["wait-for-device", "shell", "ls", "/sbin"])
+            self._checkCmd(["wait-for-device"])
+            if self._runAdbAsRoot:
+                self._adb_root()
+            self._checkCmd(["shell", "ls", "/sbin"])
 
     def updateApp(self, appBundlePath, **kwargs):
         return self._runCmd(["install", "-r", appBundlePath]).output
 
     def getCurrentTime(self):
         timestr = str(self._runCmd(["shell", "date", "+%s"]).output[0])
         if (not timestr or not timestr.isdigit()):
             raise DMError("Unable to get current time using date (got: '%s')" % timestr)
@@ -636,16 +643,19 @@ class DeviceManagerADB(DeviceManager):
             retcode = proc.poll()
         if retcode is None: # still not terminated, kill
             proc.kill()
 
         data = proc.output[0]
         if data.find('uid=0(root)') >= 0:
             self._haveSu = True
 
+        if self._runAdbAsRoot:
+            self._adb_root()
+
     def _isUnzipAvailable(self):
         data = self._runCmd(["shell", "unzip"]).output
         for line in data:
             if (re.search('Usage', line)):
                 return True
         return False
 
     def _isLocalZipAvailable(self):
@@ -660,8 +670,18 @@ class DeviceManagerADB(DeviceManager):
         # 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()):
             self._logger.info("will use zip to push directories")
             self._useZip = True
         else:
             raise DMError("zip not available")
+
+    def _adb_root(self):
+        """ Some devices require us to reboot adbd as root.
+            This function takes care of it.
+        """
+        if self.processInfo("adbd")[2] != "root":
+            self._checkCmd(["root"])
+            self._checkCmd(["wait-for-device"])
+            if self.processInfo("adbd")[2] != "root":
+                raise DMError("We tried rebooting adbd as root, however, it failed.")