Bug 1485855 - [mozdevice] adb.py Do not attempt to chmod external storage as it will not affect permissions and will fail on unrooted devices, r=jmaher.
authorBob Clary <bclary@bclary.com>
Mon, 27 Aug 2018 06:59:21 -0700
changeset 488634 b70bf5d57074ac21886a9be54dfa2cbc87030197
parent 488633 e51092dbe3ce6d2ddfd59212cf44024f93414107
child 488635 83388bace8ff0150e4811777180e51c24ddcbbc4
push id9734
push usershindli@mozilla.com
push dateThu, 30 Aug 2018 12:18:07 +0000
treeherdermozilla-beta@71c71ab3afae [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjmaher
bugs1485855
milestone63.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 1485855 - [mozdevice] adb.py Do not attempt to chmod external storage as it will not affect permissions and will fail on unrooted devices, r=jmaher.
testing/mozbase/mozdevice/mozdevice/adb.py
--- a/testing/mozbase/mozdevice/mozdevice/adb.py
+++ b/testing/mozbase/mozdevice/mozdevice/adb.py
@@ -591,16 +591,17 @@ class ADBDevice(ADBCommand):
         self._device_serial = self._get_device_serial(device)
         self._initial_test_root = test_root
         self._test_root = None
         self._device_ready_retry_wait = device_ready_retry_wait
         self._device_ready_retry_attempts = device_ready_retry_attempts
         self._have_root_shell = False
         self._have_su = False
         self._have_android_su = False
+        self._re_internal_storage = None
 
         # Catch exceptions due to the potential for segfaults
         # calling su when using an improperly rooted device.
 
         # Note this check to see if adbd is running is performed on
         # the device in the state it exists in when the ADBDevice is
         # initialized. It may be the case that it has been manipulated
         # since its last boot and that its current state does not
@@ -791,16 +792,43 @@ class ADBDevice(ADBCommand):
             exitcode = int(match.group(1))
             file_obj.seek(-1, os.SEEK_CUR)
             file_obj.truncate()
         else:
             exitcode = None
 
         return exitcode
 
+    def is_path_internal_storage(self, path, timeout=None):
+        """
+        Return True if the path matches an internal storage path
+        as defined by either '/sdcard', '/mnt/sdcard', or any of the
+        .*_STORAGE environment variables on the device otherwise False.
+        :param str path: The path to test.
+        :param timeout: The maximum time in
+            seconds for any spawned adb process to complete before
+            throwing an ADBTimeoutError.  This timeout is per adb call. The
+            total time spent may exceed this value. If it is not
+            specified, the value set in the ADBDevice constructor is used.
+        :returns: boolean
+
+        :raises: * ADBTimeoutError
+                 * ADBError
+        """
+        if not self._re_internal_storage:
+            storage_dirs = set(['/mnt/sdcard', '/sdcard'])
+            re_STORAGE = re.compile('([^=]+STORAGE)=(.*)')
+            lines = self.shell_output('set', timeout=timeout).split()
+            for line in lines:
+                m = re_STORAGE.match(line.strip())
+                if m and m.group(2):
+                    storage_dirs.add(m.group(2))
+            self._re_internal_storage = re.compile('/|'.join(list(storage_dirs)) + '/')
+        return self._re_internal_storage.match(path) is not None
+
     @property
     def test_root(self):
         """
         The test_root property returns the directory on the device where
         temporary test files are stored.
 
         The first time test_root it is called it determines and caches a value
         for the test root on the device. It determines the appropriate test
@@ -1539,16 +1567,23 @@ class ADBDevice(ADBCommand):
         # which is a symbolic link to a socket: lock ->
         # 127.0.0.1:+<port>.  On Linux, chmod -R ignores symbolic
         # links but it appear Android's version does not. We ignore
         # this type of error, but pass on any other errors that are
         # detected.
         path = posixpath.normpath(path.strip())
         self._logger.debug('chmod: path=%s, recursive=%s, mask=%s, root=%s' %
                            (path, recursive, mask, root))
+        if self.is_path_internal_storage(path, timeout=timeout):
+            # External storage on Android is case-insensitive and permissionless
+            # therefore even with the proper privileges it is not possible
+            # to change modes.
+            self._logger.warning('Ignoring attempt to chmod external storage')
+            return
+
         if not recursive:
             self.shell_output("chmod %s %s" % (mask, path),
                               timeout=timeout, root=root)
             return
 
         if self._chmod_R:
             try:
                 self.shell_output("chmod -R %s %s" % (mask, path),