[tools, scripts] (P12): tcp_device_server.py --surface window|pbuffer (default pbuffer, unchanged) starts the on-screen display Activity on a lit screen, and --backend pins either server

This commit is contained in:
2026-09-24 00:20:11 -04:00
parent 3726b1f7e5
commit 984db45576
2 changed files with 90 additions and 10 deletions
+35
View File
@@ -227,6 +227,41 @@ class DeviceIdleExemption(unittest.TestCase):
self.assertFalse(state.exists())
class DeviceServerSurface(unittest.TestCase):
"""P12 D9: tcp_device_server.py starts one of the two device servers - the offscreen
supervisor service (the default, unchanged) or the on-screen display Activity."""
def started(self, *argv):
spec = importlib.util.spec_from_file_location('tcp_device_server', ROOT / 'tools/trace_replay/tcp_device_server.py')
device = importlib.util.module_from_spec(spec)
spec.loader.exec_module(device)
commands = []
with patch.object(device, 'shell', side_effect=lambda _adb, command: commands.append(command) or ''), \
patch('builtins.print'):
device.main(['start', '--package', 'pkg', '--listen', 'tcp://127.0.0.1:40613',
'--token', 'a-token-of-sixteen-bytes', '--env', 'A=1', *argv])
return commands
def test_the_default_is_still_the_offscreen_supervisor_service(self):
self.assertEqual(self.started(), [[
'am', 'start-foreground-service', '-n', 'pkg/top.mobilegl.plugin.MobileGLServerService',
'--es', 'listen', 'tcp://127.0.0.1:40613', '--es', 'token', 'a-token-of-sixteen-bytes',
'--es', 'env', 'A=1']])
self.assertEqual(self.started('--surface', 'pbuffer'), self.started())
# A pinned backend reaches the supervisor through its environment.
self.assertEqual(self.started('--backend', 'DirectVulkan')[0][-1], 'A=1;MOBILEGL_BACKEND_TYPE=DirectVulkan')
def test_window_starts_the_display_activity_with_the_same_extras_on_a_lit_screen(self):
commands = self.started('--surface', 'window', '--backend', 'DirectVulkan')
self.assertEqual(commands, [
['input', 'keyevent', 'KEYCODE_WAKEUP'],
['am', 'start', '-n', 'pkg/top.mobilegl.plugin.MobileGLDisplayActivity',
'--es', 'listen', 'tcp://127.0.0.1:40613', '--es', 'token', 'a-token-of-sixteen-bytes',
'--es', 'env', 'A=1', '--es', 'backend', 'DirectVulkan']])
# Without --backend the Activity gets no pin extra (the first session's backend is pinned).
self.assertNotIn('backend', self.started('--surface', 'window')[1])
@unittest.skipUnless(sys.platform.startswith('linux'), 'supervisor fixture uses Linux /proc')
class Supervisor(unittest.TestCase):
def test_readiness_does_not_consume_a_connection_and_stop_owns_only_its_pid(self):
+55 -10
View File
@@ -1,5 +1,15 @@
#!/usr/bin/env python3
"""Start or stop the trace APK's foreground TCP supervisor through adb."""
"""Start or stop the trace APK's TCP server through adb.
Two servers, one at a time (P12 D8; whichever starts last owns the port):
--surface pbuffer (default) the foreground MobileGLServerService: an exec'd supervisor that forks
one offscreen session child per client (the P6.5 path).
--surface window the on-screen MobileGLDisplayActivity (process :mglwin): the server runs
in the Activity's own process and a client with MOBILEGL_IPC_SURFACE=server
renders its window surface onto the Activity's SurfaceView (P12 D7/D9).
Needs the screen on and unlocked for its Surface to exist.
`stop` force-stops the package, which ends either.
"""
import argparse
import json
from pathlib import Path
@@ -51,8 +61,29 @@ def restore_idle(adb, serial, package, state_path):
print('Restored the original device idle whitelist setting for ' + package)
def main():
parser = argparse.ArgumentParser(description=__doc__)
SERVICE = 'top.mobilegl.plugin.MobileGLServerService'
DISPLAY_ACTIVITY = 'top.mobilegl.plugin.MobileGLDisplayActivity'
def start_command(args):
"""The `am` command that starts the requested server, with the extras both servers share."""
env = list(args.env)
extras = ['--es', 'listen', args.listen, '--es', 'token', args.token]
if args.surface == 'window':
# The display Activity takes the backend as its own extra (the pin for its process).
extras += ['--es', 'env', ';'.join(env)]
if args.backend:
extras += ['--es', 'backend', args.backend]
return ['am', 'start', '-n', args.package + '/' + DISPLAY_ACTIVITY] + extras
# The supervisor pins a backend through its environment (a disagreeing Hello is refused).
if args.backend:
env.append('MOBILEGL_BACKEND_TYPE=' + args.backend)
extras += ['--es', 'env', ';'.join(env)]
return ['am', 'start-foreground-service', '-n', args.package + '/' + SERVICE] + extras
def main(argv=None):
parser = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter)
parser.add_argument('action', choices=('start', 'stop'))
parser.add_argument('--adb', default='adb')
parser.add_argument('--serial', default='2f7cbe2e')
@@ -65,7 +96,13 @@ def main():
help='Temporarily exempt this package from Doze; stop restores its previous setting')
parser.add_argument('--state-file', type=Path,
help='Saved original idle setting (default: ~/.cache/mobilegl/tcp-server/<serial>-<package>.json)')
args = parser.parse_args()
parser.add_argument('--surface', choices=('pbuffer', 'window'), default='pbuffer',
help='pbuffer (default): the offscreen supervisor service; window: the on-screen '
'display Activity (clients opt in with MOBILEGL_IPC_SURFACE=server)')
parser.add_argument('--backend', choices=('DirectGLES', 'DirectVulkan'),
help='pin the server to one backend (a client asking for the other is refused); '
'without it the on-screen server pins the first session\'s')
args = parser.parse_args(argv)
adb = [args.adb, '-s', args.serial]
state_name = re.sub(r'[^A-Za-z0-9_.-]', '_', args.serial + '-' + args.package) + '.json'
state_path = args.state_file or (Path.home() / '.cache/mobilegl/tcp-server' / state_name)
@@ -74,18 +111,26 @@ def main():
else:
if args.allow_idle:
allow_idle(adb, args.serial, args.package, state_path)
command = ['am', 'start-foreground-service', '-n', args.package + '/top.mobilegl.plugin.MobileGLServerService',
'--es', 'listen', args.listen, '--es', 'token', args.token,
'--es', 'env', ';'.join(args.env)]
if args.surface == 'window':
# The Activity's SurfaceView exists only on a lit screen.
shell(adb, ['input', 'keyevent', 'KEYCODE_WAKEUP'])
command = start_command(args)
print(shell(adb, command), end='')
if args.action == 'stop':
restore_idle(adb, args.serial, args.package, state_path)
if args.action == 'start' and args.forward:
subprocess.run(adb + ['forward', 'tcp:40613', 'tcp:40613'], check=True)
if args.action == 'start':
print('Read readiness: adb -s ' + args.serial + ' logcat -s MobileGLServer')
print('Client: MOBILEGL_TRANSPORT=spawn MOBILEGL_IPC_DATA=stream '
'MOBILEGL_IPC_REQUIRE_SAME_BUILD=1 MOBILEGL_IPC_CONTROL=tcp://<device-address>:40613')
if args.surface == 'window':
print('Read readiness: adb -s ' + args.serial + ' logcat -s MobileGL MobileGLDisplay '
'(MG_Remote server: ... listening on ... in-process display server, display installed)')
print('Client: MOBILEGL_TRANSPORT=spawn MOBILEGL_IPC_DATA=stream MOBILEGL_IPC_SURFACE=server '
'MOBILEGL_IPC_REQUIRE_SAME_BUILD=1 MOBILEGL_IPC_CONTROL=tcp://<device-address>:40613 '
'(trace_replay --window-surface)')
else:
print('Read readiness: adb -s ' + args.serial + ' logcat -s MobileGLServer')
print('Client: MOBILEGL_TRANSPORT=spawn MOBILEGL_IPC_DATA=stream '
'MOBILEGL_IPC_REQUIRE_SAME_BUILD=1 MOBILEGL_IPC_CONTROL=tcp://<device-address>:40613')
if __name__ == '__main__':