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 197993 0dff8ac3f629f6f061aa78eb5ed06e60d5748359
parent 197992 1cb5bd26726ea0c980730d1d29509446f69c7208
child 197994 8ecb3e5d5013a34c87587bb44260d9014ead2dba
push id1036
push userrnewman@mozilla.com
push dateWed, 06 Aug 2014 02:14:58 +0000
treeherderservices-central@3fd543e150c8 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerswlach
bugs1021756
milestone34.0a1
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.")