## Prerequisites
-Export the `ANDROID_HOME` environment variable to point at your Android SDK. If
-you don't already have the SDK, here's how to install it:
+First, make sure you have all the usual tools and libraries needed to build
+Python for your development machine.
+
+Second, you'll need an Android SDK. If you already have the SDK installed,
+export the `ANDROID_HOME` environment variable to point at its location.
+Otherwise, here's how to install it:
* Download the "Command line tools" from <https://developer.android.com/studio>.
* Create a directory `android-sdk/cmdline-tools`, and unzip the command line
cross-build where you use a "build" Python (for your development machine) to
help produce a "host" Python for Android.
-First, make sure you have all the usual tools and libraries needed to build
-Python for your development machine. The only Android tool you need to install
-is the command line tools package above: the build script will download the
-rest.
-
The easiest way to do a build is to use the `android.py` script. You can either
have it perform the entire build process from start to finish in one step, or
you can do it in discrete steps that mirror running `configure` and `make` for
## Testing
-The tests can be run on Linux, macOS, or Windows, although on Windows you'll
-have to build the `cross-build/HOST` subdirectory on one of the other platforms
-and copy it over.
+The test suite can be run on Linux, macOS, or Windows:
+
+* On Linux, the emulator needs access to the KVM virtualization interface, and
+ a DISPLAY environment variable pointing at an X server.
+* On Windows, you won't be able to do the build on the same machine, so you'll
+ have to copy the `cross-build/HOST` directory from somewhere else.
-The test suite can usually be run on a device with 2 GB of RAM, though for some
-configurations or test orders you may need to increase this. As of Android
+The test suite can usually be run on a device with 2 GB of RAM, but this is
+borderline, so you may need to increase it to 4 GB. As of Android
Studio Koala, 2 GB is the default for all emulators, although the user interface
may indicate otherwise. The effective setting is `hw.ramSize` in
~/.android/avd/*.avd/hardware-qemu.ini, whereas Android Studio displays the
f"{temp_dir}/{outer_jar}", "gradle-wrapper.jar"])
-# run_testbed will build the app automatically, but it hides the Gradle output
-# by default, so it's useful to have this as a separate command for the buildbot.
+# run_testbed will build the app automatically, but it's useful to have this as
+# a separate command to allow running the app outside of this script.
def build_testbed(context):
setup_sdk()
setup_testbed()
shown_error = False
while True:
try:
+ # `pidof` requires API level 24 or higher. The level 23 emulator
+ # includes it, but it doesn't work (it returns all processes).
pid = (await async_check_output(
adb, "-s", serial, "shell", "pidof", "-s", APP_ID
)).strip()
serial = await wait_for(find_device(context, initial_devices), startup_timeout)
pid = await wait_for(find_pid(serial), startup_timeout)
+ # `--pid` requires API level 24 or higher.
args = [adb, "-s", serial, "logcat", "--pid", pid, "--format", "tag"]
hidden_output = []
async with async_process(
# such messages, but other components might.
level, message = None, line
+ # Exclude high-volume messages which are rarely useful.
+ if context.verbose < 2 and "from python test_syslog" in message:
+ continue
+
# Put high-level messages on stderr so they're highlighted in the
# buildbot logs. This will include Python's own stderr.
stream = (
sys.stderr
- if level in ["E", "F"] # ERROR and FATAL (aka ASSERT)
+ if level in ["W", "E", "F"] # WARNING, ERROR, FATAL (aka ASSERT)
else sys.stdout
)
test = subcommands.add_parser(
"test", help="Run the test suite")
test.add_argument(
- "-v", "--verbose", action="store_true",
- help="Show Gradle output, and non-Python logcat messages")
+ "-v", "--verbose", action="count", default=0,
+ help="Show Gradle output, and non-Python logcat messages. "
+ "Use twice to include high-volume messages which are rarely useful.")
device_group = test.add_mutually_exclusive_group(required=True)
device_group.add_argument(
"--connected", metavar="SERIAL", help="Run on a connected device. "
def main():
install_signal_handler()
+
+ # Under the buildbot, stdout is not a TTY, but we must still flush after
+ # every line to make sure our output appears in the correct order relative
+ # to the output of our subprocesses.
+ for stream in [sys.stdout, sys.stderr]:
+ stream.reconfigure(line_buffering=True)
+
context = parse_args()
dispatch = {"configure-build": configure_build_python,
"make-build": make_build_python,