workspace := "/srv/android-automotive" release := "imx-automotive-16.0.0_1.1.0" source_tree := workspace / release / "android_build" images_dir := workspace / "releases" / release build_container := "android-automotive-build" nxp_build_image := "android-build-nxp" build_image := "android-build" mrs_build_dockerfile := workspace / "Dockerfile.android-build" os_src := workspace / "os" os_dest := source_tree / "device" / "mrs" platform_manifest := workspace / "mrs-platform.xml" cuttlefish_runtime := workspace / "cuttlefish-mrs" userid := `id -u` groupid := `getent group android-build | cut -d: -f3` default: @just --list install-repo: sudo curl https://storage.googleapis.com/git-repo-downloads/repo -o /usr/local/bin/repo sudo chmod +x /usr/local/bin/repo extract-bsp archive=(release + ".tar.gz"): cd {{workspace}} && tar -xzvf {{archive}} # Install the local manifest that replaces four upstream Android projects with # exact revisions from the MRS platform repositories. _install-platform-manifest: mkdir -p {{source_tree}}/.repo/local_manifests install -m 0644 {{platform_manifest}} {{source_tree}}/.repo/local_manifests/mrs-platform.xml # Synchronize every project in the NXP/AOSP checkout. This is an explicit # maintenance operation, not part of the routine build path. sync-source: _install-platform-manifest cd {{source_tree}} && repo sync --detach --fail-fast # Synchronize only the checkout paths replaced by mrs-platform.xml. Repo reads # their MRS GitLab remotes and pinned revisions from the installed local # manifest, so it does not scan or update the rest of the Android checkout. sync-os: _install-platform-manifest cd {{source_tree}} && repo sync --detach --fail-fast \ packages/apps/Car/Launcher \ system/core \ hardware/interfaces \ device/google/cuttlefish # MRS-owned products and new files are not Repo projects; copy them separately. mkdir -p {{os_dest}} rsync -av --delete {{os_src}}/ {{os_dest}}/ build-container: @bash {{workspace}}/build-time.sh {{workspace}}/build-metadata/build-container.txt build-container bash -lc "cd {{source_tree}}/device/nxp/common/dockerbuild && docker build --no-cache \ --build-arg userid=\$(id -u) \ --build-arg groupid=\$(id -g) \ --build-arg username=\$(id -un) \ -t {{nxp_build_image}} . && \ docker build --no-cache \ --build-arg BASE_IMAGE={{nxp_build_image}} \ -t {{build_image}} \ - < {{mrs_build_dockerfile}}" build-module module: sync-os @rm -rf {{images_dir}} @docker rm -f {{build_container}} 2>/dev/null || true @docker run -d \ --name {{build_container}} \ --entrypoint /bin/bash \ -u {{userid}}:{{groupid}} \ -v {{source_tree}}:/work/android_src \ -v {{workspace}}:/work/workspace \ -v {{workspace}}/releases:/work/releases \ {{build_image}} \ -lc 'bash /work/workspace/build-time.sh /work/releases/{{release}}/apps/{{module}}/build-time.txt build-module bash -lc "set -e; \ cd /work/android_src && \ source build/envsetup.sh && \ lunch mrs_mek_8q-nxp_stable-userdebug && \ m {{module}} && \ mkdir -p /work/releases/{{release}}/apps/{{module}} && \ apk_path=$(find out/target/product/mrs_mek_8q -path \"*/{{module}}/{{module}}.apk\" | head -n 1) && \ test -f \"\$apk_path\" && \ cp -v \"\$apk_path\" /work/releases/{{release}}/apps/{{module}}/"' @echo "Module build started. Use 'docker ps' to check status and 'docker logs -f {{build_container}}' to view output." _run-build target variant out_dir="out": sync-os #!/usr/bin/env bash set -euo pipefail variant="{{variant}}" case "{{target}}" in mek_8q) variant="${variant:-userdebug}" lunch_target="mrs_mek_8q-nxp_stable-${variant}" build_command="device/mrs/imx8q-common/build.sh device/mrs/mrs_mek_8q -j2" artifact_script='cd {{out_dir}}/target/product/mrs_mek_8q && for pattern in boot.img boot-imx.img init_boot.img vendor_boot.img vendor_boot-debug.img super.img super_empty.img partition-table.img partition-table-13GB.img partition-table-dual.img partition-table-13GB-dual.img dtbo.img dtbo-*.img vbmeta.img vbmeta-*.img u-boot-imx8qm.imx u-boot-imx8qm-md.imx u-boot-imx8qm-mek-uuu.imx uuu_imx_android_flash.sh; do cp -v $pattern /work/releases/{{release}}/mek_8q/ 2>/dev/null || true; done' ;; neuralplex) variant="${variant:-userdebug}" lunch_target="neuralplex-nxp_stable-${variant}" build_command="device/mrs/imx8q-common/build.sh device/mrs/neuralplex -j2" artifact_script='cd {{out_dir}}/target/product/neuralplex && for pattern in boot.img boot-imx.img init_boot.img vendor_boot.img vendor_boot-debug.img super.img super_empty.img partition-table.img partition-table-13GB.img partition-table-dual.img partition-table-13GB-dual.img dtbo.img dtbo-*.img vbmeta.img vbmeta-*.img u-boot-imx8qm.imx u-boot-imx8qm-md.imx u-boot-imx8qm-mek-uuu.imx uuu_imx_android_flash.sh; do cp -v $pattern /work/releases/{{release}}/neuralplex/ 2>/dev/null || true; done' ;; cuttlefish) variant="${variant:-eng}" lunch_target="mrs_cuttlefish-bp2a-${variant}" build_command="m dist" artifact_script='cd {{out_dir}}/dist && for pattern in cvd-host_package.tar.gz *-img-*.zip; do cp -v $pattern /work/releases/{{release}}/cuttlefish/ 2>/dev/null || true; done' ;; *) echo "unknown target: {{target}} (expected mek_8q, neuralplex, or cuttlefish)" >&2 exit 2 ;; esac echo "Fixing permissions on source tree..." sudo find {{source_tree}} ! -group {{groupid}} -print0 | xargs -0 -r chgrp -hv {{groupid}} 2>/dev/null || true rm -rf {{images_dir}}/{{target}} docker rm -f {{build_container}} 2>/dev/null || true docker run -d \ --name {{build_container}} \ --entrypoint /bin/bash \ -u {{userid}}:{{groupid}} \ -v {{source_tree}}:/work/android_src \ -v {{workspace}}:/work/workspace \ -v {{workspace}}/releases:/work/releases \ {{build_image}} \ -lc "bash /work/workspace/build-time.sh /work/releases/{{release}}/{{target}}/build-time.txt build-{{target}} bash -lc 'set -e; \ cd /work/android_src && \ export OUT_DIR={{out_dir}} && \ source build/envsetup.sh && \ lunch $lunch_target && \ $build_command 2>&1 && \ rm -rf /work/releases/{{release}}/{{target}} && \ mkdir -p /work/releases/{{release}}/{{target}} && \ $artifact_script'" echo "Build started. Use 'docker ps' to check status and 'docker logs -f {{build_container}}' to view output." build target variant="": (_run-build target variant) build-release target: (_run-build target "user" "out-release") launch-cuttlefish runtime_dir=cuttlefish_runtime: #!/usr/bin/env bash set -euo pipefail runtime_dir="{{runtime_dir}}" artifacts_dir={{images_dir}}/cuttlefish host_package="$artifacts_dir/cvd-host_package.tar.gz" image_zip=$(find "$artifacts_dir" -maxdepth 1 -name '*-img-*.zip' | sort | tail -n 1) uid=$(id -u) test -f "$host_package" test -n "$image_zip" if [ -e "$runtime_dir" ] || pgrep -f "$runtime_dir" >/dev/null 2>&1 || \ [ -e "/tmp/cf_avd_${uid}" ] || [ -e "/tmp/cf_env_${uid}" ] || \ find /tmp -maxdepth 1 -name "vsock_*_${uid}" | grep -q .; then echo "existing Cuttlefish runtime state detected; run 'just stop-cuttlefish' and retry" >&2 exit 1 fi mkdir -p "$runtime_dir" tar -xf "$host_package" -C "$runtime_dir" unzip -oq "$image_zip" -d "$runtime_dir" truncate -s 8G "$runtime_dir/userdata.img" # --daemon keeps its foreground parent alive until the guest reaches a # final boot state. Do not terminate that parent: the daemon reports boot # completion through it and exits if the pipe is closed early. HOME="$runtime_dir" "$runtime_dir/bin/launch_cvd" \ --daemon \ --noresume \ --console=true \ -data_policy=always_create \ -blank_data_image_mb=8192 \ -report_anonymous_usage_stats=n # Auto-stop after 2 hours if still running setsid bash -c ' sleep 7200 if pgrep -f "'"$runtime_dir"'/bin" >/dev/null 2>&1; then just stop-cuttlefish "'"$runtime_dir"'" fi ' >/dev/null 2>&1 & echo "Cuttlefish will auto-stop in 2 hours if still running." console-cuttlefish runtime_dir=cuttlefish_runtime: #!/usr/bin/env bash set -euo pipefail console_path="{{runtime_dir}}/cuttlefish/instances/cvd-1/console" if [ ! -e "$console_path" ]; then echo "Cuttlefish serial console not found at $console_path" >&2 echo "Run 'just launch-cuttlefish' first." >&2 exit 1 fi exec tio "$console_path" stop-cuttlefish runtime_dir=cuttlefish_runtime: #!/usr/bin/env bash set -euo pipefail runtime_dir="{{runtime_dir}}" uid=$(id -u) graceful_stopped=false if [ -x "$runtime_dir/bin/stop_cvd" ]; then if HOME="$runtime_dir" "$runtime_dir/bin/stop_cvd" >/dev/null 2>&1; then graceful_stopped=true else echo "graceful stop unavailable; cleaning stale runtime state" >&2 fi fi pkill -f "$runtime_dir" 2>/dev/null || true sleep 2 pkill -9 -f "$runtime_dir" 2>/dev/null || true rm -rf "$runtime_dir" "/tmp/cf_avd_${uid}" "/tmp/cf_env_${uid}" find /tmp -maxdepth 1 -name "vsock_*_${uid}" -exec rm -rf {} + if [ "$graceful_stopped" = true ]; then echo "Cuttlefish stopped cleanly" else echo "Cuttlefish runtime state cleaned" fi clean-build: rm -rf {{source_tree}}/out clean-release-build: rm -rf {{source_tree}}/out-release clean-artifacts: rm -rf {{images_dir}}