diff --git a/.devcontainer/android/Dockerfile b/.devcontainer/android/Dockerfile new file mode 100644 index 00000000000..bccd154b82b --- /dev/null +++ b/.devcontainer/android/Dockerfile @@ -0,0 +1,61 @@ +ARG VARIANT="8.0-jammy" +FROM mcr.microsoft.com/devcontainers/dotnet:${VARIANT} + +# Set up machine requirements to build the repo +RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \ + && apt-get -y install --no-install-recommends \ + cmake \ + llvm \ + clang \ + build-essential \ + python3 \ + curl \ + git \ + lldb \ + liblldb-dev \ + libunwind8 \ + libunwind8-dev \ + gettext \ + libicu-dev \ + liblttng-ust-dev \ + libssl-dev \ + libkrb5-dev \ + zlib1g-dev \ + ninja-build \ + openjdk-17-jdk \ + pulseaudio + +SHELL ["/bin/bash", "-c"] + +ENV NDK_VER=r23c +ENV SDK_VER=9123335_latest +ENV SDK_API_LEVEL=33 +ENV SDK_BUILD_TOOLS=33.0.1 +ENV HOST_OS=linux +ENV HOST_OS_SHORT=linux +ENV ANDROID_NDK_ROOT=/android/android-ndk-${NDK_VER} +ENV ANDROID_SDK_ROOT=/android/android-sdk +ENV EMULATOR_NAME_X64=dotnet-android-emulator + +# Download Android NDK and SDK +RUN curl -sSL --tlsv1.2 https://dl.google.com/android/repository/android-ndk-${NDK_VER}-${HOST_OS}.zip -L --output /tmp/andk.zip && \ + curl -sSL --tlsv1.2 https://dl.google.com/android/repository/commandlinetools-${HOST_OS_SHORT}-${SDK_VER}.zip -L --output /tmp/asdk.zip + +# Check hashes of downloads +RUN (echo "6ce94604b77d28113ecd588d425363624a5228d9662450c48d2e4053f8039242 /tmp/andk.zip"; echo "0bebf59339eaa534f4217f8aa0972d14dc49e7207be225511073c661ae01da0a /tmp/asdk.zip") | cat | sha256sum -c + +# Unpack the NDK and SDK +RUN mkdir -p ${ANDROID_NDK_ROOT} && unzip /tmp/andk.zip -d $(dirname ${ANDROID_NDK_ROOT}) && rm -f /tmp/andk.zip && \ + mkdir -p ${ANDROID_SDK_ROOT} && unzip /tmp/asdk.zip -d ${ANDROID_SDK_ROOT}/cmdline-tools && rm -f /tmp/asdk.zip + +# Setup the SDK +RUN yes | ${ANDROID_SDK_ROOT}/cmdline-tools/cmdline-tools/bin/sdkmanager --sdk_root=${ANDROID_SDK_ROOT} --licenses && \ + ${ANDROID_SDK_ROOT}/cmdline-tools/cmdline-tools/bin/sdkmanager --sdk_root=${ANDROID_SDK_ROOT} "platform-tools" "platforms;android-${SDK_API_LEVEL}" "build-tools;${SDK_BUILD_TOOLS}" + +# Install an x86_64 emulator +RUN ${ANDROID_SDK_ROOT}/cmdline-tools/cmdline-tools/bin/sdkmanager --sdk_root=${ANDROID_SDK_ROOT} "system-images;android-${SDK_API_LEVEL};default;x86_64" + +# Setup kvm group. We need the group ID to be GID owner of /dev/kvm. +# Then add the vscode user to the kvm group. +RUN groupadd -r -g 109 kvm && \ + gpasswd -a vscode kvm diff --git a/.devcontainer/android/devcontainer.json b/.devcontainer/android/devcontainer.json new file mode 100644 index 00000000000..9bfc25bd6cf --- /dev/null +++ b/.devcontainer/android/devcontainer.json @@ -0,0 +1,63 @@ +// For format details, see https://aka.ms/devcontainer.json. +{ + "name": "Libraries/Runtime Android development (prebuilt)", + "build": { + "dockerfile": "Dockerfile", + "args": { + "VARIANT": "8.0-jammy" + } + }, + // The container needs to run privileged in order to use Linux KVM to create Android emulators. + "runArgs": [ + "--privileged", + "--security-opt", + "seccomp=unconfined" + ], + "hostRequirements": { + "cpus": 4, + "memory": "8gb", + "storage": "64gb" + }, + + "features": { + "ghcr.io/devcontainers/features/github-cli:1": {} + }, + + // Configure tool-specific properties. + "customizations": { + // Configure properties specific to VS Code. + "vscode": { + // Add the IDs of extensions you want installed when the container is created. + "extensions": [ + "ms-dotnettools.csharp" + ], + "settings": { + // Loading projects on demand is better for larger codebases + "omnisharp.enableMsBuildLoadProjectsOnDemand": true, + "omnisharp.enableRoslynAnalyzers": true, + "omnisharp.enableEditorConfigSupport": true, + "omnisharp.enableAsyncCompletion": true, + "omnisharp.testRunSettings": "${containerWorkspaceFolder}/artifacts/obj/vscode/.runsettings" + } + } + }, + + // Use 'onCreateCommand' to run pre-build commands inside the codespace + "onCreateCommand": "${containerWorkspaceFolder}/.devcontainer/scripts/onCreateCommand.sh android", + + // Use 'postCreateCommand' to run commands after the container is created. + "postCreateCommand": "${containerWorkspaceFolder}/.devcontainer/scripts/postCreateCommand.sh android", + + "postStartCommand": "${containerWorkspaceFolder}/.devcontainer/android/postStartCommand.sh", + + // Add the locally installed dotnet to the path to ensure that it is activated + // This allows developers to just use 'dotnet build' on the command-line, and the local dotnet version will be used. + // Add the Android SDK tooling and emulator to the path. + "remoteEnv": { + "PATH": "${containerWorkspaceFolder}/.dotnet:${containerEnv:ANDROID_SDK_ROOT}/cmdline-tools/cmdline-tools/bin:${containerEnv:ANDROID_SDK_ROOT}/emulator:${containerEnv:ANDROID_SDK_ROOT}/platform-tools:${containerEnv:PATH}", + "DOTNET_MULTILEVEL_LOOKUP": "0" + }, + + // Comment out connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root. + "remoteUser": "vscode" +} diff --git a/.devcontainer/android/postStartCommand.sh b/.devcontainer/android/postStartCommand.sh new file mode 100755 index 00000000000..b2c67d1164f --- /dev/null +++ b/.devcontainer/android/postStartCommand.sh @@ -0,0 +1,10 @@ +#!/usr/bin/env bash + +set -e + +# Start the emulator. +# Use nohup to start a shell so that things run in the background. +# Use flock to make sure we have only one running emulator. +# Background flock +# nohup stdout and stderr goes to /dev/null, otherwise it's going to write to a file. +nohup bash -c 'flock -n /var/lock/emulator.lock -c '\''${ANDROID_SDK_ROOT}/emulator/emulator -avd ${EMULATOR_NAME_X64} -no-window -no-audio -no-snapstorage'\''&' >/dev/null 2>&1 diff --git a/.devcontainer/scripts/onCreateCommand.sh b/.devcontainer/scripts/onCreateCommand.sh index 1fcee604b35..5afcc900153 100755 --- a/.devcontainer/scripts/onCreateCommand.sh +++ b/.devcontainer/scripts/onCreateCommand.sh @@ -12,6 +12,13 @@ case "$opt" in ./build.sh libs.tests -restore ;; + android) + # prebuild the repo for Mono, so it is ready for development + ./build.sh mono+libs -os android + # restore libs tests so that the project is ready to be loaded by OmniSharp + ./build.sh libs.tests -restore + ;; + wasm) # prebuild for WASM, so it is ready for wasm development make -C src/mono/wasm provision-wasm diff --git a/.devcontainer/scripts/postCreateCommand.sh b/.devcontainer/scripts/postCreateCommand.sh index 8086037ab9a..b50fb9a7009 100755 --- a/.devcontainer/scripts/postCreateCommand.sh +++ b/.devcontainer/scripts/postCreateCommand.sh @@ -2,5 +2,13 @@ set -e +opt=$1 +case "$opt" in + android) + # Create the Android emulator. + ${ANDROID_SDK_ROOT}/cmdline-tools/cmdline-tools/bin/avdmanager -s create avd --name ${EMULATOR_NAME_X64} --package "system-images;android-${SDK_API_LEVEL};default;x86_64" + ;; +esac + # reset the repo to the commit hash that was used to build the prebuilt Codespace git reset --hard $(cat ./artifacts/prebuild.sha)