1
0
mirror of https://github.com/ARM-software/devlib.git synced 2025-03-04 17:27:51 +00:00

utils/android: Restore adb root state when disconnecting

The current behavior is to issue "adb unroot" if the device needed to be
rooted upon connection. This breaks use of nested Targets, which LISA
requires as some target interaction needs to happen in a subprocess.

Fix that by restoring the same adb root state that there was when
creating the connection, rather than blindly unrooting the device upon
disconnection.
This commit is contained in:
Douglas Raillard 2025-02-04 16:15:04 +00:00 committed by Marc Bonnici
parent f60fa59ac1
commit 20e5bcd2c7

View File

@ -305,13 +305,14 @@ class AdbConnection(ConnectionBase):
self.adb_server = adb_server self.adb_server = adb_server
self.adb_port = adb_port self.adb_port = adb_port
self.adb_as_root = adb_as_root self.adb_as_root = adb_as_root
self._restore_to_adb_root = False
lock, nr_active = AdbConnection.active_connections lock, nr_active = AdbConnection.active_connections
with lock: with lock:
nr_active[self.device] += 1 nr_active[self.device] += 1
if self.adb_as_root: if self.adb_as_root:
try: try:
self.adb_root(enable=True) self._restore_to_adb_root = self._adb_root(enable=True)
# Exception will be raised if we are not the only connection # Exception will be raised if we are not the only connection
# active. adb_root() requires restarting the server, which is not # active. adb_root() requires restarting the server, which is not
# acceptable if other connections are active and can apparently # acceptable if other connections are active and can apparently
@ -405,7 +406,7 @@ class AdbConnection(ConnectionBase):
if disconnect: if disconnect:
if self.adb_as_root: if self.adb_as_root:
self.adb_root(enable=False) self.adb_root(enable=self._restore_to_adb_root)
adb_disconnect(self.device, self.adb_server, self.adb_port) adb_disconnect(self.device, self.adb_server, self.adb_port)
def cancel_running_command(self): def cancel_running_command(self):
@ -415,6 +416,9 @@ class AdbConnection(ConnectionBase):
pass pass
def adb_root(self, enable=True): def adb_root(self, enable=True):
self._adb_root(enable=enable)
def _adb_root(self, enable):
lock, nr_active = AdbConnection.active_connections lock, nr_active = AdbConnection.active_connections
with lock: with lock:
can_root = nr_active[self.device] <= 1 can_root = nr_active[self.device] <= 1
@ -422,20 +426,24 @@ class AdbConnection(ConnectionBase):
if not can_root: if not can_root:
raise AdbRootError('Can only restart adb server if no other connection is active') raise AdbRootError('Can only restart adb server if no other connection is active')
def is_rooted(out):
return 'adbd is already running as root' in out
cmd = 'root' if enable else 'unroot' cmd = 'root' if enable else 'unroot'
try: try:
output = adb_command(self.device, cmd, timeout=30, adb_server=self.adb_server, adb_port=self.adb_port) output = adb_command(self.device, cmd, timeout=30, adb_server=self.adb_server, adb_port=self.adb_port)
except subprocess.CalledProcessError as e: except subprocess.CalledProcessError as e:
was_rooted = is_rooted(e.output)
# Ignore if we're already root # Ignore if we're already root
if 'adbd is already running as root' in e.output: if not was_rooted:
pass
else:
raise AdbRootError(str(e)) from e raise AdbRootError(str(e)) from e
else: else:
was_rooted = is_rooted(output)
# Check separately as this does not cause a error exit code. # Check separately as this does not cause a error exit code.
if 'cannot run as root in production builds' in output: if 'cannot run as root in production builds' in output:
raise AdbRootError(output) raise AdbRootError(output)
AdbConnection._connected_as_root[self.device] = enable AdbConnection._connected_as_root[self.device] = enable
return was_rooted
def wait_for_device(self, timeout=30): def wait_for_device(self, timeout=30):
adb_command(self.device, 'wait-for-device', timeout, self.adb_server, self.adb_port) adb_command(self.device, 'wait-for-device', timeout, self.adb_server, self.adb_port)