xref: /aosp_15_r20/tools/treble/build/sandbox/nsjail.py (revision 105f628577ac4ba0e277a494fbb614ed8c12a994)
1*105f6285SAndroid Build Coastguard Worker# Copyright 2020 Google LLC
2*105f6285SAndroid Build Coastguard Worker#
3*105f6285SAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License");
4*105f6285SAndroid Build Coastguard Worker# you may not use this file except in compliance with the License.
5*105f6285SAndroid Build Coastguard Worker# You may obtain a copy of the License at
6*105f6285SAndroid Build Coastguard Worker#
7*105f6285SAndroid Build Coastguard Worker#     https://www.apache.org/licenses/LICENSE-2.0
8*105f6285SAndroid Build Coastguard Worker#
9*105f6285SAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software
10*105f6285SAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS,
11*105f6285SAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*105f6285SAndroid Build Coastguard Worker# See the License for the specific language governing permissions and
13*105f6285SAndroid Build Coastguard Worker# limitations under the License.
14*105f6285SAndroid Build Coastguard Worker
15*105f6285SAndroid Build Coastguard Worker"""Runs a command inside an NsJail sandbox for building Android.
16*105f6285SAndroid Build Coastguard Worker
17*105f6285SAndroid Build Coastguard WorkerNsJail creates a user namespace sandbox where
18*105f6285SAndroid Build Coastguard WorkerAndroid can be built in an isolated process.
19*105f6285SAndroid Build Coastguard WorkerIf no command is provided then it will open
20*105f6285SAndroid Build Coastguard Workeran interactive bash shell.
21*105f6285SAndroid Build Coastguard Worker"""
22*105f6285SAndroid Build Coastguard Worker
23*105f6285SAndroid Build Coastguard Workerimport argparse
24*105f6285SAndroid Build Coastguard Workerimport collections
25*105f6285SAndroid Build Coastguard Workerimport os
26*105f6285SAndroid Build Coastguard Workerimport re
27*105f6285SAndroid Build Coastguard Workerimport subprocess
28*105f6285SAndroid Build Coastguard Workerfrom . import config
29*105f6285SAndroid Build Coastguard Workerfrom .overlay import BindMount
30*105f6285SAndroid Build Coastguard Workerfrom .overlay import BindOverlay
31*105f6285SAndroid Build Coastguard Worker
32*105f6285SAndroid Build Coastguard Worker_DEFAULT_META_ANDROID_DIR = 'LINUX/android'
33*105f6285SAndroid Build Coastguard Worker_DEFAULT_COMMAND = '/bin/bash'
34*105f6285SAndroid Build Coastguard Worker
35*105f6285SAndroid Build Coastguard Worker_SOURCE_MOUNT_POINT = '/src'
36*105f6285SAndroid Build Coastguard Worker_OUT_MOUNT_POINT = '/src/out'
37*105f6285SAndroid Build Coastguard Worker_DIST_MOUNT_POINT = '/dist'
38*105f6285SAndroid Build Coastguard Worker_META_MOUNT_POINT = '/meta'
39*105f6285SAndroid Build Coastguard Worker
40*105f6285SAndroid Build Coastguard Worker_CHROOT_MOUNT_POINTS = [
41*105f6285SAndroid Build Coastguard Worker  'bin', 'sbin',
42*105f6285SAndroid Build Coastguard Worker  'etc/alternatives', 'etc/default', 'etc/perl',
43*105f6285SAndroid Build Coastguard Worker  'etc/ssl', 'etc/xml',
44*105f6285SAndroid Build Coastguard Worker  'lib', 'lib32', 'lib64', 'libx32',
45*105f6285SAndroid Build Coastguard Worker  'usr',
46*105f6285SAndroid Build Coastguard Worker]
47*105f6285SAndroid Build Coastguard Worker
48*105f6285SAndroid Build Coastguard Worker
49*105f6285SAndroid Build Coastguard Workerdef run(command,
50*105f6285SAndroid Build Coastguard Worker        build_target,
51*105f6285SAndroid Build Coastguard Worker        nsjail_bin,
52*105f6285SAndroid Build Coastguard Worker        chroot,
53*105f6285SAndroid Build Coastguard Worker        overlay_config=None,
54*105f6285SAndroid Build Coastguard Worker        source_dir=os.getcwd(),
55*105f6285SAndroid Build Coastguard Worker        dist_dir=None,
56*105f6285SAndroid Build Coastguard Worker        build_id=None,
57*105f6285SAndroid Build Coastguard Worker        out_dir = None,
58*105f6285SAndroid Build Coastguard Worker        meta_root_dir = None,
59*105f6285SAndroid Build Coastguard Worker        meta_android_dir = _DEFAULT_META_ANDROID_DIR,
60*105f6285SAndroid Build Coastguard Worker        mount_local_device = False,
61*105f6285SAndroid Build Coastguard Worker        max_cpus=None,
62*105f6285SAndroid Build Coastguard Worker        extra_bind_mounts=[],
63*105f6285SAndroid Build Coastguard Worker        readonly_bind_mounts=[],
64*105f6285SAndroid Build Coastguard Worker        extra_nsjail_args=[],
65*105f6285SAndroid Build Coastguard Worker        dry_run=False,
66*105f6285SAndroid Build Coastguard Worker        quiet=False,
67*105f6285SAndroid Build Coastguard Worker        env=[],
68*105f6285SAndroid Build Coastguard Worker        nsjail_wrapper=[],
69*105f6285SAndroid Build Coastguard Worker        stdout=None,
70*105f6285SAndroid Build Coastguard Worker        stderr=None,
71*105f6285SAndroid Build Coastguard Worker        allow_network=False):
72*105f6285SAndroid Build Coastguard Worker  """Run inside an NsJail sandbox.
73*105f6285SAndroid Build Coastguard Worker
74*105f6285SAndroid Build Coastguard Worker  Args:
75*105f6285SAndroid Build Coastguard Worker    command: A list of strings with the command to run.
76*105f6285SAndroid Build Coastguard Worker    build_target: A string with the name of the build target to be prepared
77*105f6285SAndroid Build Coastguard Worker      inside the container.
78*105f6285SAndroid Build Coastguard Worker    nsjail_bin: A string with the path to the nsjail binary.
79*105f6285SAndroid Build Coastguard Worker    chroot: A string with the path to the chroot.
80*105f6285SAndroid Build Coastguard Worker    overlay_config: A string path to an overlay configuration file.
81*105f6285SAndroid Build Coastguard Worker    source_dir: A string with the path to the Android platform source.
82*105f6285SAndroid Build Coastguard Worker    dist_dir: A string with the path to the dist directory.
83*105f6285SAndroid Build Coastguard Worker    build_id: A string with the build identifier.
84*105f6285SAndroid Build Coastguard Worker    out_dir: An optional path to the Android build out folder.
85*105f6285SAndroid Build Coastguard Worker    meta_root_dir: An optional path to a folder containing the META build.
86*105f6285SAndroid Build Coastguard Worker    meta_android_dir: An optional path to the location where the META build expects
87*105f6285SAndroid Build Coastguard Worker      the Android build. This path must be relative to meta_root_dir.
88*105f6285SAndroid Build Coastguard Worker    mount_local_device: Whether to mount /dev/usb (and related) trees enabling
89*105f6285SAndroid Build Coastguard Worker      adb to run inside the jail
90*105f6285SAndroid Build Coastguard Worker    max_cpus: An integer with maximum number of CPUs.
91*105f6285SAndroid Build Coastguard Worker    extra_bind_mounts: An array of extra mounts in the 'source' or 'source:dest' syntax.
92*105f6285SAndroid Build Coastguard Worker    readonly_bind_mounts: An array of read only mounts in the 'source' or 'source:dest' syntax.
93*105f6285SAndroid Build Coastguard Worker    extra_nsjail_args: A list of strings that contain extra arguments to nsjail.
94*105f6285SAndroid Build Coastguard Worker    dry_run: If true, the command will be returned but not executed
95*105f6285SAndroid Build Coastguard Worker    quiet: If true, the function will not display the command and
96*105f6285SAndroid Build Coastguard Worker      will pass -quiet argument to nsjail
97*105f6285SAndroid Build Coastguard Worker    env: An array of environment variables to define in the jail in the `var=val` syntax.
98*105f6285SAndroid Build Coastguard Worker    nsjail_wrapper: A list of strings used to wrap the nsjail command.
99*105f6285SAndroid Build Coastguard Worker    stdout: the standard output for all printed messages. Valid values are None, a file
100*105f6285SAndroid Build Coastguard Worker      descriptor or file object. A None value means sys.stdout is used.
101*105f6285SAndroid Build Coastguard Worker    stderr: the standard error for all printed messages. Valid values are None, a file
102*105f6285SAndroid Build Coastguard Worker      descriptor or file object, and subprocess.STDOUT (which indicates that all stderr
103*105f6285SAndroid Build Coastguard Worker      should be redirected to stdout). A None value means sys.stderr is used.
104*105f6285SAndroid Build Coastguard Worker    allow_network: allow access to host network
105*105f6285SAndroid Build Coastguard Worker
106*105f6285SAndroid Build Coastguard Worker  Returns:
107*105f6285SAndroid Build Coastguard Worker    A list of strings with the command executed.
108*105f6285SAndroid Build Coastguard Worker  """
109*105f6285SAndroid Build Coastguard Worker
110*105f6285SAndroid Build Coastguard Worker
111*105f6285SAndroid Build Coastguard Worker  nsjail_command = get_command(
112*105f6285SAndroid Build Coastguard Worker      command=command,
113*105f6285SAndroid Build Coastguard Worker      build_target=build_target,
114*105f6285SAndroid Build Coastguard Worker      nsjail_bin=nsjail_bin,
115*105f6285SAndroid Build Coastguard Worker      chroot=chroot,
116*105f6285SAndroid Build Coastguard Worker      cfg=config.factory(overlay_config),
117*105f6285SAndroid Build Coastguard Worker      source_dir=source_dir,
118*105f6285SAndroid Build Coastguard Worker      dist_dir=dist_dir,
119*105f6285SAndroid Build Coastguard Worker      build_id=build_id,
120*105f6285SAndroid Build Coastguard Worker      out_dir=out_dir,
121*105f6285SAndroid Build Coastguard Worker      meta_root_dir=meta_root_dir,
122*105f6285SAndroid Build Coastguard Worker      meta_android_dir=meta_android_dir,
123*105f6285SAndroid Build Coastguard Worker      mount_local_device=mount_local_device,
124*105f6285SAndroid Build Coastguard Worker      max_cpus=max_cpus,
125*105f6285SAndroid Build Coastguard Worker      extra_bind_mounts=extra_bind_mounts,
126*105f6285SAndroid Build Coastguard Worker      readonly_bind_mounts=readonly_bind_mounts,
127*105f6285SAndroid Build Coastguard Worker      extra_nsjail_args=extra_nsjail_args,
128*105f6285SAndroid Build Coastguard Worker      quiet=quiet,
129*105f6285SAndroid Build Coastguard Worker      env=env,
130*105f6285SAndroid Build Coastguard Worker      nsjail_wrapper=nsjail_wrapper,
131*105f6285SAndroid Build Coastguard Worker      allow_network=allow_network)
132*105f6285SAndroid Build Coastguard Worker
133*105f6285SAndroid Build Coastguard Worker  run_command(
134*105f6285SAndroid Build Coastguard Worker      nsjail_command=nsjail_command,
135*105f6285SAndroid Build Coastguard Worker      mount_local_device=mount_local_device,
136*105f6285SAndroid Build Coastguard Worker      dry_run=dry_run,
137*105f6285SAndroid Build Coastguard Worker      quiet=quiet,
138*105f6285SAndroid Build Coastguard Worker      stdout=stdout,
139*105f6285SAndroid Build Coastguard Worker      stderr=stderr)
140*105f6285SAndroid Build Coastguard Worker
141*105f6285SAndroid Build Coastguard Worker  return nsjail_command
142*105f6285SAndroid Build Coastguard Worker
143*105f6285SAndroid Build Coastguard Workerdef get_command(command,
144*105f6285SAndroid Build Coastguard Worker        build_target,
145*105f6285SAndroid Build Coastguard Worker        nsjail_bin,
146*105f6285SAndroid Build Coastguard Worker        chroot,
147*105f6285SAndroid Build Coastguard Worker        cfg=None,
148*105f6285SAndroid Build Coastguard Worker        source_dir=os.getcwd(),
149*105f6285SAndroid Build Coastguard Worker        dist_dir=None,
150*105f6285SAndroid Build Coastguard Worker        build_id=None,
151*105f6285SAndroid Build Coastguard Worker        out_dir = None,
152*105f6285SAndroid Build Coastguard Worker        meta_root_dir = None,
153*105f6285SAndroid Build Coastguard Worker        meta_android_dir = _DEFAULT_META_ANDROID_DIR,
154*105f6285SAndroid Build Coastguard Worker        mount_local_device = False,
155*105f6285SAndroid Build Coastguard Worker        max_cpus=None,
156*105f6285SAndroid Build Coastguard Worker        extra_bind_mounts=[],
157*105f6285SAndroid Build Coastguard Worker        readonly_bind_mounts=[],
158*105f6285SAndroid Build Coastguard Worker        extra_nsjail_args=[],
159*105f6285SAndroid Build Coastguard Worker        quiet=False,
160*105f6285SAndroid Build Coastguard Worker        env=[],
161*105f6285SAndroid Build Coastguard Worker        nsjail_wrapper=[],
162*105f6285SAndroid Build Coastguard Worker        allow_network=False):
163*105f6285SAndroid Build Coastguard Worker  """Get command to run nsjail sandbox.
164*105f6285SAndroid Build Coastguard Worker
165*105f6285SAndroid Build Coastguard Worker  Args:
166*105f6285SAndroid Build Coastguard Worker    command: A list of strings with the command to run.
167*105f6285SAndroid Build Coastguard Worker    build_target: A string with the name of the build target to be prepared
168*105f6285SAndroid Build Coastguard Worker      inside the container.
169*105f6285SAndroid Build Coastguard Worker    nsjail_bin: A string with the path to the nsjail binary.
170*105f6285SAndroid Build Coastguard Worker    chroot: A string with the path to the chroot.
171*105f6285SAndroid Build Coastguard Worker    cfg: A config.Config instance or None.
172*105f6285SAndroid Build Coastguard Worker    source_dir: A string with the path to the Android platform source.
173*105f6285SAndroid Build Coastguard Worker    dist_dir: A string with the path to the dist directory.
174*105f6285SAndroid Build Coastguard Worker    build_id: A string with the build identifier.
175*105f6285SAndroid Build Coastguard Worker    out_dir: An optional path to the Android build out folder.
176*105f6285SAndroid Build Coastguard Worker    meta_root_dir: An optional path to a folder containing the META build.
177*105f6285SAndroid Build Coastguard Worker    meta_android_dir: An optional path to the location where the META build expects
178*105f6285SAndroid Build Coastguard Worker      the Android build. This path must be relative to meta_root_dir.
179*105f6285SAndroid Build Coastguard Worker    max_cpus: An integer with maximum number of CPUs.
180*105f6285SAndroid Build Coastguard Worker    extra_bind_mounts: An array of extra mounts in the 'source' or 'source:dest' syntax.
181*105f6285SAndroid Build Coastguard Worker    readonly_bind_mounts: An array of read only mounts in the 'source' or 'source:dest' syntax.
182*105f6285SAndroid Build Coastguard Worker    extra_nsjail_args: A list of strings that contain extra arguments to nsjail.
183*105f6285SAndroid Build Coastguard Worker    quiet: If true, the function will not display the command and
184*105f6285SAndroid Build Coastguard Worker      will pass -quiet argument to nsjail
185*105f6285SAndroid Build Coastguard Worker    env: An array of environment variables to define in the jail in the `var=val` syntax.
186*105f6285SAndroid Build Coastguard Worker    allow_network: allow access to host network
187*105f6285SAndroid Build Coastguard Worker
188*105f6285SAndroid Build Coastguard Worker  Returns:
189*105f6285SAndroid Build Coastguard Worker    A list of strings with the command to execute.
190*105f6285SAndroid Build Coastguard Worker  """
191*105f6285SAndroid Build Coastguard Worker  script_dir = os.path.dirname(os.path.abspath(__file__))
192*105f6285SAndroid Build Coastguard Worker  config_file = os.path.join(script_dir, 'nsjail.cfg')
193*105f6285SAndroid Build Coastguard Worker
194*105f6285SAndroid Build Coastguard Worker  # Run expects absolute paths
195*105f6285SAndroid Build Coastguard Worker  if out_dir:
196*105f6285SAndroid Build Coastguard Worker    out_dir = os.path.abspath(out_dir)
197*105f6285SAndroid Build Coastguard Worker  if dist_dir:
198*105f6285SAndroid Build Coastguard Worker    dist_dir = os.path.abspath(dist_dir)
199*105f6285SAndroid Build Coastguard Worker  if meta_root_dir:
200*105f6285SAndroid Build Coastguard Worker    meta_root_dir = os.path.abspath(meta_root_dir)
201*105f6285SAndroid Build Coastguard Worker  if source_dir:
202*105f6285SAndroid Build Coastguard Worker    source_dir = os.path.abspath(source_dir)
203*105f6285SAndroid Build Coastguard Worker
204*105f6285SAndroid Build Coastguard Worker  if nsjail_bin:
205*105f6285SAndroid Build Coastguard Worker    nsjail_bin = os.path.join(source_dir, nsjail_bin)
206*105f6285SAndroid Build Coastguard Worker
207*105f6285SAndroid Build Coastguard Worker  if chroot:
208*105f6285SAndroid Build Coastguard Worker    chroot = os.path.join(source_dir, chroot)
209*105f6285SAndroid Build Coastguard Worker
210*105f6285SAndroid Build Coastguard Worker  if meta_root_dir:
211*105f6285SAndroid Build Coastguard Worker    if not meta_android_dir or os.path.isabs(meta_android_dir):
212*105f6285SAndroid Build Coastguard Worker      raise ValueError('error: the provided meta_android_dir is not a path'
213*105f6285SAndroid Build Coastguard Worker          'relative to meta_root_dir.')
214*105f6285SAndroid Build Coastguard Worker
215*105f6285SAndroid Build Coastguard Worker  nsjail_command = nsjail_wrapper + [nsjail_bin,
216*105f6285SAndroid Build Coastguard Worker    '--env', 'USER=nobody',
217*105f6285SAndroid Build Coastguard Worker    '--config', config_file]
218*105f6285SAndroid Build Coastguard Worker
219*105f6285SAndroid Build Coastguard Worker  # By mounting the points individually that we need we reduce exposure and
220*105f6285SAndroid Build Coastguard Worker  # keep the chroot clean from artifacts
221*105f6285SAndroid Build Coastguard Worker  if chroot:
222*105f6285SAndroid Build Coastguard Worker    for mpoints in _CHROOT_MOUNT_POINTS:
223*105f6285SAndroid Build Coastguard Worker      source = os.path.join(chroot, mpoints)
224*105f6285SAndroid Build Coastguard Worker      dest = os.path.join('/', mpoints)
225*105f6285SAndroid Build Coastguard Worker      if os.path.exists(source):
226*105f6285SAndroid Build Coastguard Worker        nsjail_command.extend([
227*105f6285SAndroid Build Coastguard Worker          '--bindmount_ro', '%s:%s' % (source, dest)
228*105f6285SAndroid Build Coastguard Worker        ])
229*105f6285SAndroid Build Coastguard Worker
230*105f6285SAndroid Build Coastguard Worker  if build_id:
231*105f6285SAndroid Build Coastguard Worker    nsjail_command.extend(['--env', 'BUILD_NUMBER=%s' % build_id])
232*105f6285SAndroid Build Coastguard Worker  if max_cpus:
233*105f6285SAndroid Build Coastguard Worker    nsjail_command.append('--max_cpus=%i' % max_cpus)
234*105f6285SAndroid Build Coastguard Worker  if quiet:
235*105f6285SAndroid Build Coastguard Worker    nsjail_command.append('--quiet')
236*105f6285SAndroid Build Coastguard Worker
237*105f6285SAndroid Build Coastguard Worker  whiteout_list = set()
238*105f6285SAndroid Build Coastguard Worker  if out_dir and (
239*105f6285SAndroid Build Coastguard Worker      os.path.dirname(out_dir) == source_dir) and (
240*105f6285SAndroid Build Coastguard Worker      os.path.basename(out_dir) != 'out'):
241*105f6285SAndroid Build Coastguard Worker    whiteout_list.add(os.path.abspath(out_dir))
242*105f6285SAndroid Build Coastguard Worker    if not os.path.exists(out_dir):
243*105f6285SAndroid Build Coastguard Worker      os.makedirs(out_dir)
244*105f6285SAndroid Build Coastguard Worker
245*105f6285SAndroid Build Coastguard Worker  # Apply the overlay for the selected Android target to the source directory
246*105f6285SAndroid Build Coastguard Worker  # from the supplied config.Config instance (which may be None).
247*105f6285SAndroid Build Coastguard Worker  if cfg is not None:
248*105f6285SAndroid Build Coastguard Worker    overlay = BindOverlay(build_target,
249*105f6285SAndroid Build Coastguard Worker                      source_dir,
250*105f6285SAndroid Build Coastguard Worker                      cfg,
251*105f6285SAndroid Build Coastguard Worker                      whiteout_list,
252*105f6285SAndroid Build Coastguard Worker                      _SOURCE_MOUNT_POINT,
253*105f6285SAndroid Build Coastguard Worker                      quiet=quiet)
254*105f6285SAndroid Build Coastguard Worker    bind_mounts = overlay.GetBindMounts()
255*105f6285SAndroid Build Coastguard Worker  else:
256*105f6285SAndroid Build Coastguard Worker    bind_mounts = collections.OrderedDict()
257*105f6285SAndroid Build Coastguard Worker    bind_mounts[_SOURCE_MOUNT_POINT] = BindMount(source_dir, False, False)
258*105f6285SAndroid Build Coastguard Worker
259*105f6285SAndroid Build Coastguard Worker  if out_dir:
260*105f6285SAndroid Build Coastguard Worker    bind_mounts[_OUT_MOUNT_POINT] = BindMount(out_dir, False, False)
261*105f6285SAndroid Build Coastguard Worker
262*105f6285SAndroid Build Coastguard Worker  if dist_dir:
263*105f6285SAndroid Build Coastguard Worker    bind_mounts[_DIST_MOUNT_POINT] = BindMount(dist_dir, False, False)
264*105f6285SAndroid Build Coastguard Worker    nsjail_command.extend([
265*105f6285SAndroid Build Coastguard Worker        '--env', 'DIST_DIR=%s'%_DIST_MOUNT_POINT
266*105f6285SAndroid Build Coastguard Worker    ])
267*105f6285SAndroid Build Coastguard Worker
268*105f6285SAndroid Build Coastguard Worker  if meta_root_dir:
269*105f6285SAndroid Build Coastguard Worker    bind_mounts[_META_MOUNT_POINT] = BindMount(meta_root_dir, False, False)
270*105f6285SAndroid Build Coastguard Worker    bind_mounts[os.path.join(_META_MOUNT_POINT, meta_android_dir)] = BindMount(source_dir, False, False)
271*105f6285SAndroid Build Coastguard Worker    if out_dir:
272*105f6285SAndroid Build Coastguard Worker      bind_mounts[os.path.join(_META_MOUNT_POINT, meta_android_dir, 'out')] = BindMount(out_dir, False, False)
273*105f6285SAndroid Build Coastguard Worker
274*105f6285SAndroid Build Coastguard Worker  for bind_destination, bind_mount in bind_mounts.items():
275*105f6285SAndroid Build Coastguard Worker    if bind_mount.readonly:
276*105f6285SAndroid Build Coastguard Worker      nsjail_command.extend([
277*105f6285SAndroid Build Coastguard Worker        '--bindmount_ro',  bind_mount.source_dir + ':' + bind_destination
278*105f6285SAndroid Build Coastguard Worker      ])
279*105f6285SAndroid Build Coastguard Worker    else:
280*105f6285SAndroid Build Coastguard Worker      nsjail_command.extend([
281*105f6285SAndroid Build Coastguard Worker        '--bindmount',  bind_mount.source_dir + ':' + bind_destination
282*105f6285SAndroid Build Coastguard Worker      ])
283*105f6285SAndroid Build Coastguard Worker
284*105f6285SAndroid Build Coastguard Worker  if mount_local_device:
285*105f6285SAndroid Build Coastguard Worker    # Mount /dev/bus/usb and several /sys/... paths, which adb will examine
286*105f6285SAndroid Build Coastguard Worker    # while attempting to find the attached android device. These paths expose
287*105f6285SAndroid Build Coastguard Worker    # a lot of host operating system device space, so it's recommended to use
288*105f6285SAndroid Build Coastguard Worker    # the mount_local_device option only when you need to use adb (e.g., for
289*105f6285SAndroid Build Coastguard Worker    # atest or some other purpose).
290*105f6285SAndroid Build Coastguard Worker    nsjail_command.extend(['--bindmount', '/dev/bus/usb'])
291*105f6285SAndroid Build Coastguard Worker    nsjail_command.extend(['--bindmount', '/sys/bus/usb/devices'])
292*105f6285SAndroid Build Coastguard Worker    nsjail_command.extend(['--bindmount', '/sys/dev'])
293*105f6285SAndroid Build Coastguard Worker    nsjail_command.extend(['--bindmount', '/sys/devices'])
294*105f6285SAndroid Build Coastguard Worker
295*105f6285SAndroid Build Coastguard Worker  for mount in extra_bind_mounts:
296*105f6285SAndroid Build Coastguard Worker    nsjail_command.extend(['--bindmount', mount])
297*105f6285SAndroid Build Coastguard Worker  for mount in readonly_bind_mounts:
298*105f6285SAndroid Build Coastguard Worker    nsjail_command.extend(['--bindmount_ro', mount])
299*105f6285SAndroid Build Coastguard Worker
300*105f6285SAndroid Build Coastguard Worker  for var in env:
301*105f6285SAndroid Build Coastguard Worker    nsjail_command.extend(['--env', var])
302*105f6285SAndroid Build Coastguard Worker
303*105f6285SAndroid Build Coastguard Worker  if allow_network:
304*105f6285SAndroid Build Coastguard Worker    nsjail_command.extend(['--disable_clone_newnet',
305*105f6285SAndroid Build Coastguard Worker                           '--bindmount_ro',
306*105f6285SAndroid Build Coastguard Worker                           '/etc/resolv.conf'])
307*105f6285SAndroid Build Coastguard Worker
308*105f6285SAndroid Build Coastguard Worker  nsjail_command.extend(extra_nsjail_args)
309*105f6285SAndroid Build Coastguard Worker
310*105f6285SAndroid Build Coastguard Worker  nsjail_command.append('--')
311*105f6285SAndroid Build Coastguard Worker  nsjail_command.extend(command)
312*105f6285SAndroid Build Coastguard Worker
313*105f6285SAndroid Build Coastguard Worker  return nsjail_command
314*105f6285SAndroid Build Coastguard Worker
315*105f6285SAndroid Build Coastguard Workerdef run_command(nsjail_command,
316*105f6285SAndroid Build Coastguard Worker                mount_local_device=False,
317*105f6285SAndroid Build Coastguard Worker                dry_run=False,
318*105f6285SAndroid Build Coastguard Worker                quiet=False,
319*105f6285SAndroid Build Coastguard Worker                stdout=None,
320*105f6285SAndroid Build Coastguard Worker                stderr=None):
321*105f6285SAndroid Build Coastguard Worker  """Run the provided nsjail command.
322*105f6285SAndroid Build Coastguard Worker
323*105f6285SAndroid Build Coastguard Worker  Args:
324*105f6285SAndroid Build Coastguard Worker    nsjail_command: A list of strings with the command to run.
325*105f6285SAndroid Build Coastguard Worker    mount_local_device: Whether to mount /dev/usb (and related) trees enabling
326*105f6285SAndroid Build Coastguard Worker      adb to run inside the jail
327*105f6285SAndroid Build Coastguard Worker    dry_run: If true, the command will be returned but not executed
328*105f6285SAndroid Build Coastguard Worker    quiet: If true, the function will not display the command and
329*105f6285SAndroid Build Coastguard Worker      will pass -quiet argument to nsjail
330*105f6285SAndroid Build Coastguard Worker    stdout: the standard output for all printed messages. Valid values are None, a file
331*105f6285SAndroid Build Coastguard Worker      descriptor or file object. A None value means sys.stdout is used.
332*105f6285SAndroid Build Coastguard Worker    stderr: the standard error for all printed messages. Valid values are None, a file
333*105f6285SAndroid Build Coastguard Worker      descriptor or file object, and subprocess.STDOUT (which indicates that all stderr
334*105f6285SAndroid Build Coastguard Worker      should be redirected to stdout). A None value means sys.stderr is used.
335*105f6285SAndroid Build Coastguard Worker  """
336*105f6285SAndroid Build Coastguard Worker
337*105f6285SAndroid Build Coastguard Worker  if mount_local_device:
338*105f6285SAndroid Build Coastguard Worker    # A device can only communicate with one adb server at a time, so the adb server is
339*105f6285SAndroid Build Coastguard Worker    # killed on the host machine.
340*105f6285SAndroid Build Coastguard Worker    for line in subprocess.check_output(['ps','-eo','cmd']).decode().split('\n'):
341*105f6285SAndroid Build Coastguard Worker      if re.match(r'adb.*fork-server.*', line):
342*105f6285SAndroid Build Coastguard Worker        print('An adb server is running on your host machine. This server must be '
343*105f6285SAndroid Build Coastguard Worker              'killed to use the --mount_local_device flag.')
344*105f6285SAndroid Build Coastguard Worker        print('Continue? [y/N]: ', end='')
345*105f6285SAndroid Build Coastguard Worker        if input().lower() != 'y':
346*105f6285SAndroid Build Coastguard Worker          exit()
347*105f6285SAndroid Build Coastguard Worker        subprocess.check_call(['adb', 'kill-server'])
348*105f6285SAndroid Build Coastguard Worker
349*105f6285SAndroid Build Coastguard Worker  if not quiet:
350*105f6285SAndroid Build Coastguard Worker    print('NsJail command:', file=stdout)
351*105f6285SAndroid Build Coastguard Worker    print(' '.join(nsjail_command), file=stdout)
352*105f6285SAndroid Build Coastguard Worker
353*105f6285SAndroid Build Coastguard Worker  if not dry_run:
354*105f6285SAndroid Build Coastguard Worker    try:
355*105f6285SAndroid Build Coastguard Worker      subprocess.check_call(nsjail_command, stdout=stdout, stderr=stderr)
356*105f6285SAndroid Build Coastguard Worker    except subprocess.CalledProcessError as error:
357*105f6285SAndroid Build Coastguard Worker      if len(error.cmd) > 13:
358*105f6285SAndroid Build Coastguard Worker        cmd = error.cmd[:6] + ['...elided...'] + error.cmd[-6:]
359*105f6285SAndroid Build Coastguard Worker      else:
360*105f6285SAndroid Build Coastguard Worker        cmd = error.cmd
361*105f6285SAndroid Build Coastguard Worker      msg = 'nsjail command %s failed with return code %d' % (cmd, error.returncode)
362*105f6285SAndroid Build Coastguard Worker      # Raise from None to avoid exception chaining.
363*105f6285SAndroid Build Coastguard Worker      raise RuntimeError(msg) from None
364*105f6285SAndroid Build Coastguard Worker
365*105f6285SAndroid Build Coastguard Worker
366*105f6285SAndroid Build Coastguard Workerdef parse_args():
367*105f6285SAndroid Build Coastguard Worker  """Parse command line arguments.
368*105f6285SAndroid Build Coastguard Worker
369*105f6285SAndroid Build Coastguard Worker  Returns:
370*105f6285SAndroid Build Coastguard Worker    An argparse.Namespace object.
371*105f6285SAndroid Build Coastguard Worker  """
372*105f6285SAndroid Build Coastguard Worker
373*105f6285SAndroid Build Coastguard Worker  # Use the top level module docstring for the help description
374*105f6285SAndroid Build Coastguard Worker  parser = argparse.ArgumentParser(
375*105f6285SAndroid Build Coastguard Worker      description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter)
376*105f6285SAndroid Build Coastguard Worker  parser.add_argument(
377*105f6285SAndroid Build Coastguard Worker      '--nsjail_bin',
378*105f6285SAndroid Build Coastguard Worker      required=True,
379*105f6285SAndroid Build Coastguard Worker      help='Path to NsJail binary.')
380*105f6285SAndroid Build Coastguard Worker  parser.add_argument(
381*105f6285SAndroid Build Coastguard Worker      '--chroot',
382*105f6285SAndroid Build Coastguard Worker      help='Path to the chroot to be used for building the Android'
383*105f6285SAndroid Build Coastguard Worker      'platform. This will be mounted as the root filesystem in the'
384*105f6285SAndroid Build Coastguard Worker      'NsJail sandbox.')
385*105f6285SAndroid Build Coastguard Worker  parser.add_argument(
386*105f6285SAndroid Build Coastguard Worker      '--overlay_config',
387*105f6285SAndroid Build Coastguard Worker      help='Path to the overlay configuration file.')
388*105f6285SAndroid Build Coastguard Worker  parser.add_argument(
389*105f6285SAndroid Build Coastguard Worker      '--source_dir',
390*105f6285SAndroid Build Coastguard Worker      default=os.getcwd(),
391*105f6285SAndroid Build Coastguard Worker      help='Path to Android platform source to be mounted as /src.')
392*105f6285SAndroid Build Coastguard Worker  parser.add_argument(
393*105f6285SAndroid Build Coastguard Worker      '--out_dir',
394*105f6285SAndroid Build Coastguard Worker      help='Full path to the Android build out folder. If not provided, uses '
395*105f6285SAndroid Build Coastguard Worker      'the standard \'out\' folder in the current path.')
396*105f6285SAndroid Build Coastguard Worker  parser.add_argument(
397*105f6285SAndroid Build Coastguard Worker      '--meta_root_dir',
398*105f6285SAndroid Build Coastguard Worker      default='',
399*105f6285SAndroid Build Coastguard Worker      help='Full path to META folder. Default to \'\'')
400*105f6285SAndroid Build Coastguard Worker  parser.add_argument(
401*105f6285SAndroid Build Coastguard Worker      '--meta_android_dir',
402*105f6285SAndroid Build Coastguard Worker      default=_DEFAULT_META_ANDROID_DIR,
403*105f6285SAndroid Build Coastguard Worker      help='Relative path to the location where the META build expects '
404*105f6285SAndroid Build Coastguard Worker      'the Android build. This path must be relative to meta_root_dir. '
405*105f6285SAndroid Build Coastguard Worker      'Defaults to \'%s\'' % _DEFAULT_META_ANDROID_DIR)
406*105f6285SAndroid Build Coastguard Worker  parser.add_argument(
407*105f6285SAndroid Build Coastguard Worker      '--command',
408*105f6285SAndroid Build Coastguard Worker      default=_DEFAULT_COMMAND,
409*105f6285SAndroid Build Coastguard Worker      help='Command to run after entering the NsJail.'
410*105f6285SAndroid Build Coastguard Worker      'If not set then an interactive Bash shell will be launched')
411*105f6285SAndroid Build Coastguard Worker  parser.add_argument(
412*105f6285SAndroid Build Coastguard Worker      '--build_target',
413*105f6285SAndroid Build Coastguard Worker      required=True,
414*105f6285SAndroid Build Coastguard Worker      help='Android target selected for building')
415*105f6285SAndroid Build Coastguard Worker  parser.add_argument(
416*105f6285SAndroid Build Coastguard Worker      '--dist_dir',
417*105f6285SAndroid Build Coastguard Worker      help='Path to the Android dist directory. This is where'
418*105f6285SAndroid Build Coastguard Worker      'Android platform release artifacts will be written.'
419*105f6285SAndroid Build Coastguard Worker      'If unset then the Android platform default will be used.')
420*105f6285SAndroid Build Coastguard Worker  parser.add_argument(
421*105f6285SAndroid Build Coastguard Worker      '--build_id',
422*105f6285SAndroid Build Coastguard Worker      help='Build identifier what will label the Android platform'
423*105f6285SAndroid Build Coastguard Worker      'release artifacts.')
424*105f6285SAndroid Build Coastguard Worker  parser.add_argument(
425*105f6285SAndroid Build Coastguard Worker      '--max_cpus',
426*105f6285SAndroid Build Coastguard Worker      type=int,
427*105f6285SAndroid Build Coastguard Worker      help='Limit of concurrent CPU cores that the NsJail sandbox'
428*105f6285SAndroid Build Coastguard Worker      'can use. Defaults to unlimited.')
429*105f6285SAndroid Build Coastguard Worker  parser.add_argument(
430*105f6285SAndroid Build Coastguard Worker      '--bindmount',
431*105f6285SAndroid Build Coastguard Worker      type=str,
432*105f6285SAndroid Build Coastguard Worker      default=[],
433*105f6285SAndroid Build Coastguard Worker      action='append',
434*105f6285SAndroid Build Coastguard Worker      help='List of mountpoints to be mounted. Can be specified multiple times. '
435*105f6285SAndroid Build Coastguard Worker      'Syntax: \'source\' or \'source:dest\'')
436*105f6285SAndroid Build Coastguard Worker  parser.add_argument(
437*105f6285SAndroid Build Coastguard Worker      '--bindmount_ro',
438*105f6285SAndroid Build Coastguard Worker      type=str,
439*105f6285SAndroid Build Coastguard Worker      default=[],
440*105f6285SAndroid Build Coastguard Worker      action='append',
441*105f6285SAndroid Build Coastguard Worker      help='List of mountpoints to be mounted read-only. Can be specified multiple times. '
442*105f6285SAndroid Build Coastguard Worker      'Syntax: \'source\' or \'source:dest\'')
443*105f6285SAndroid Build Coastguard Worker  parser.add_argument(
444*105f6285SAndroid Build Coastguard Worker      '--dry_run',
445*105f6285SAndroid Build Coastguard Worker      action='store_true',
446*105f6285SAndroid Build Coastguard Worker      help='Prints the command without executing')
447*105f6285SAndroid Build Coastguard Worker  parser.add_argument(
448*105f6285SAndroid Build Coastguard Worker      '--quiet', '-q',
449*105f6285SAndroid Build Coastguard Worker      action='store_true',
450*105f6285SAndroid Build Coastguard Worker      help='Suppress debugging output')
451*105f6285SAndroid Build Coastguard Worker  parser.add_argument(
452*105f6285SAndroid Build Coastguard Worker      '--mount_local_device',
453*105f6285SAndroid Build Coastguard Worker      action='store_true',
454*105f6285SAndroid Build Coastguard Worker      help='If provided, mount locally connected Android USB devices inside '
455*105f6285SAndroid Build Coastguard Worker      'the container. WARNING: Using this flag will cause the adb server to be '
456*105f6285SAndroid Build Coastguard Worker      'killed on the host machine. WARNING: Using this flag exposes parts of '
457*105f6285SAndroid Build Coastguard Worker      'the host /sys/... file system. Use only when you need adb.')
458*105f6285SAndroid Build Coastguard Worker  parser.add_argument(
459*105f6285SAndroid Build Coastguard Worker      '--env', '-e',
460*105f6285SAndroid Build Coastguard Worker      type=str,
461*105f6285SAndroid Build Coastguard Worker      default=[],
462*105f6285SAndroid Build Coastguard Worker      action='append',
463*105f6285SAndroid Build Coastguard Worker      help='Specify an environment variable to the NSJail sandbox. Can be specified '
464*105f6285SAndroid Build Coastguard Worker      'muliple times. Syntax: var_name=value')
465*105f6285SAndroid Build Coastguard Worker  parser.add_argument(
466*105f6285SAndroid Build Coastguard Worker      '--allow_network', action='store_true',
467*105f6285SAndroid Build Coastguard Worker      help='If provided, allow access to the host network. WARNING: Using this '
468*105f6285SAndroid Build Coastguard Worker      'flag exposes the network inside jail. Use only when needed.')
469*105f6285SAndroid Build Coastguard Worker  return parser.parse_args()
470*105f6285SAndroid Build Coastguard Worker
471*105f6285SAndroid Build Coastguard Workerdef run_with_args(args):
472*105f6285SAndroid Build Coastguard Worker  """Run inside an NsJail sandbox.
473*105f6285SAndroid Build Coastguard Worker
474*105f6285SAndroid Build Coastguard Worker  Use the arguments from an argspace namespace.
475*105f6285SAndroid Build Coastguard Worker
476*105f6285SAndroid Build Coastguard Worker  Args:
477*105f6285SAndroid Build Coastguard Worker    An argparse.Namespace object.
478*105f6285SAndroid Build Coastguard Worker
479*105f6285SAndroid Build Coastguard Worker  Returns:
480*105f6285SAndroid Build Coastguard Worker    A list of strings with the commands executed.
481*105f6285SAndroid Build Coastguard Worker  """
482*105f6285SAndroid Build Coastguard Worker  run(chroot=args.chroot,
483*105f6285SAndroid Build Coastguard Worker      nsjail_bin=args.nsjail_bin,
484*105f6285SAndroid Build Coastguard Worker      overlay_config=args.overlay_config,
485*105f6285SAndroid Build Coastguard Worker      source_dir=args.source_dir,
486*105f6285SAndroid Build Coastguard Worker      command=args.command.split(),
487*105f6285SAndroid Build Coastguard Worker      build_target=args.build_target,
488*105f6285SAndroid Build Coastguard Worker      dist_dir=args.dist_dir,
489*105f6285SAndroid Build Coastguard Worker      build_id=args.build_id,
490*105f6285SAndroid Build Coastguard Worker      out_dir=args.out_dir,
491*105f6285SAndroid Build Coastguard Worker      meta_root_dir=args.meta_root_dir,
492*105f6285SAndroid Build Coastguard Worker      meta_android_dir=args.meta_android_dir,
493*105f6285SAndroid Build Coastguard Worker      mount_local_device=args.mount_local_device,
494*105f6285SAndroid Build Coastguard Worker      max_cpus=args.max_cpus,
495*105f6285SAndroid Build Coastguard Worker      extra_bind_mounts=args.bindmount,
496*105f6285SAndroid Build Coastguard Worker      readonly_bind_mounts=args.bindmount_ro,
497*105f6285SAndroid Build Coastguard Worker      dry_run=args.dry_run,
498*105f6285SAndroid Build Coastguard Worker      quiet=args.quiet,
499*105f6285SAndroid Build Coastguard Worker      env=args.env,
500*105f6285SAndroid Build Coastguard Worker      allow_network=args.allow_network)
501*105f6285SAndroid Build Coastguard Worker
502*105f6285SAndroid Build Coastguard Workerdef main():
503*105f6285SAndroid Build Coastguard Worker  run_with_args(parse_args())
504*105f6285SAndroid Build Coastguard Worker
505*105f6285SAndroid Build Coastguard Workerif __name__ == '__main__':
506*105f6285SAndroid Build Coastguard Worker  main()
507