|
1 |
| -Cross Compilation for Android on Linux |
2 |
| -====================================== |
| 1 | +# Experimental support of CoreCLR on Android |
3 | 2 |
|
4 |
| -Through cross compilation, on Linux it is possible to build CoreCLR for arm64 Android. |
| 3 | +This is the internal documentation which outlines experimental support of CoreCLR on Android and includes instructions on how to: |
| 4 | +- [Build CoreCLR for Android](./android.md#building-coreclr-for-android) |
| 5 | +- [Build and run a sample application with CoreCLR](./android.md#building-and-running-a-sample-app) |
| 6 | +- [Debug the sample app and the runtime](./android.md#debugging-the-runtime-and-the-sample-app) |
5 | 7 |
|
6 |
| -Requirements |
7 |
| ------------- |
| 8 | +## Prerequisite |
8 | 9 |
|
9 |
| -You'll need to generate a toolchain and a sysroot for Android. There's a script which takes care of the required steps. |
| 10 | +- Download and install [OpenJDK 23](https://openjdk.org/projects/jdk/23/) |
| 11 | +- Download and install [Android Studio](https://developer.android.com/studio/install) and the following: |
| 12 | + - Android SDK (minimum supported API level is 21) |
| 13 | + - Android NDK r27 |
10 | 14 |
|
11 |
| -Generating the rootfs |
12 |
| ---------------------- |
| 15 | +> [!NOTE] |
| 16 | +> Prerequisites can also be downloaded and installed manually: |
| 17 | +> - by running the automated script as described in [Testing Libraries on Android](../../testing/libraries/testing-android.md#using-a-terminal) |
| 18 | +> - by downloading the archives: |
| 19 | +> - Android SDK - Download [command-line tools](https://developer.android.com/studio#command-line-tools-only) and use `sdkmanager` to download the SDK. |
| 20 | +> - Android NDK - Download [NDK](https://developer.android.com/ndk/downloads) |
13 | 21 |
|
14 |
| -To generate the rootfs, run the following command in the `coreclr` folder: |
| 22 | +## Building CoreCLR for Android |
| 23 | + |
| 24 | +Supported host systems for building CoreCLR for Android: |
| 25 | +- [MacOS](./android.md#macos-and-linux) ✔ |
| 26 | +- [Linux](./android.md#macos-and-linux) ✔ |
| 27 | +- [Windows](./android.md#windows) ❌ (only through WSL) |
| 28 | + |
| 29 | +Supported target architectures: |
| 30 | +- x86 ❌ |
| 31 | +- x64 ✔ |
| 32 | +- arm ❌ |
| 33 | +- arm64 ✔ |
| 34 | + |
| 35 | +### MacOS and Linux |
| 36 | + |
| 37 | +#### Requirements |
| 38 | + |
| 39 | +Set the following environment variables: |
| 40 | + - ANDROID_SDK_ROOT=`<full-path-to-android-sdk>` |
| 41 | + - ANDROID_NDK_ROOT=`<full-path-to-android-ndk>` |
| 42 | + |
| 43 | +#### Building the runtime, libraries and tools |
| 44 | + |
| 45 | +To build CoreCLR runtime, libraries and tools for local development, run the following command from `<repo-root>`: |
15 | 46 |
|
16 | 47 | ```
|
17 |
| -cross/init-android-rootfs.sh |
| 48 | +./build.sh clr.runtime+clr.alljits+clr.corelib+clr.nativecorelib+clr.tools+clr.packages+libs -os android -arch <x64|arm64> -c <Debug|Release> |
18 | 49 | ```
|
19 | 50 |
|
20 |
| -This will download the NDK and any packages required to compile Android on your system. It's over 1 GB of data, so it may take a while. |
| 51 | +To build CoreCLR runtime NuGet packages, run the following command from `<repo-root>`: |
| 52 | + |
| 53 | +``` |
| 54 | +./build.sh clr.runtime+clr.alljits+clr.corelib+clr.nativecorelib+clr.tools+clr.packages+libs+host+packs -os android -arch <x64|arm64> -c <Debug|Release> |
| 55 | +``` |
21 | 56 |
|
| 57 | +> [!NOTE] |
| 58 | +> The runtime packages will be located at: `<repo-root>/artifacts/packages/<configuration>/Shipping/` |
22 | 59 |
|
23 |
| -Cross compiling CoreCLR |
24 |
| ------------------------ |
25 |
| -Once the rootfs has been generated, it will be possible to cross compile CoreCLR. |
| 60 | +### Windows |
26 | 61 |
|
27 |
| -When cross compiling, you need to set both the `CONFIG_DIR` and `ROOTFS_DIR` variables. |
| 62 | +Building on Windows is not directly supported yet. However it is possible to use WSL2 for this purpose. |
28 | 63 |
|
29 |
| -To compile for arm64, run: |
| 64 | +#### WSL2 |
| 65 | + |
| 66 | +##### Requirements |
| 67 | + |
| 68 | +1. Install the Android SDK and NDK in WSL per the [prerequisites](#prerequisite). This can be done by downloading the archives or using Android Studio. |
| 69 | +- In case of Android Studio: |
| 70 | + - Make sure WSL is updated: from Windows host, `wsl --update` |
| 71 | + - [Enabled systemd](https://devblogs.microsoft.com/commandline/systemd-support-is-now-available-in-wsl/#set-the-systemd-flag-set-in-your-wsl-distro-settings) |
| 72 | + - `sudo snap install android-studio --classic` |
| 73 | +2. Set the following environment variables: |
| 74 | + - ANDROID_SDK_ROOT=`<full-path-to-android-sdk>` |
| 75 | + - ANDROID_NDK_ROOT=`<full-path-to-android-ndk>` |
| 76 | + |
| 77 | +#### Building the runtime, libraries and tools |
| 78 | + |
| 79 | +To build CoreCLR runtime, libraries and tools, run the following command from `<repo-root>`: |
30 | 80 |
|
31 | 81 | ```
|
32 |
| -CONFIG_DIR=`realpath cross/android/arm64` ROOTFS_DIR=`realpath cross/android-rootfs/toolchain/arm64/sysroot` ./build.sh cross arm64 cmakeargs -DENABLE_LLDBPLUGIN=0 |
| 82 | +./build.sh clr.runtime+clr.alljits+clr.corelib+clr.nativecorelib+clr.tools+clr.packages+libs -os android -arch <x64|arm64> -c <Debug|Release> |
33 | 83 | ```
|
34 | 84 |
|
35 |
| -The resulting binaries will be found in `artifacts/bin/coreclr/Linux.BuildArch.BuildType/` |
| 85 | +## Building and running a sample app |
| 86 | + |
| 87 | +To demonstrate building and running an Android sample application with CoreCLR, we will use: |
| 88 | +- the [HelloAndroid sample app](../../../../src/mono/sample/Android/AndroidSampleApp.csproj). |
| 89 | +- a functional tests [Android.Device_Emulator.JIT.Test](../../../../src/tests/FunctionalTests/Android/Device_Emulator/JIT/Android.Device_Emulator.JIT.Test.csproj) |
36 | 90 |
|
37 |
| -Running the PAL tests on Android |
38 |
| --------------------------------- |
| 91 | +A prerequisite for building and running samples locally is to have CoreCLR successfully built for desired Android platform. |
39 | 92 |
|
40 |
| -You can run the PAL tests on an Android device. To run the tests, you first copy the PAL tests to your Android phone using |
41 |
| -`adb`, and then run them in an interactive Android shell using `adb shell`: |
| 93 | +### Building HelloAndroid sample |
| 94 | + |
| 95 | +To build `HelloAndroid`, run the following command from `<repo_root>`: |
42 | 96 |
|
43 |
| -To copy the PAL tests over to an Android phone: |
44 | 97 | ```
|
45 |
| -adb push artifacts/obj/coreclr/Linux.arm64.Debug/src/pal/tests/palsuite/ /data/local/tmp/coreclr/pal/tests/palsuite |
46 |
| -adb push cross/android/toolchain/arm64/sysroot/usr/lib/libandroid-support.so /data/local/tmp/coreclr/lib/ |
47 |
| -adb push cross/android/toolchain/arm64/sysroot/usr/lib/libandroid-glob.so /data/local/tmp/coreclr/lib/ |
48 |
| -adb push src/pal/tests/palsuite/paltestlist.txt /data/local/tmp/coreclr |
49 |
| -adb push src/pal/tests/palsuite/runpaltests.sh /data/local/tmp/coreclr/ |
| 98 | +make BUILD_CONFIG=<Debug|Release> TARGET_ARCH=<x64|arm64> RUNTIME_FLAVOR=CoreCLR DEPLOY_AND_RUN=false run -C src/mono/sample/Android |
50 | 99 | ```
|
51 | 100 |
|
52 |
| -Then, use `adb shell` to launch a shell on Android. Inside that shell, you can launch the PAL tests: |
| 101 | +On successful execution, the command will output the `HelloAndroid.apk` at: |
53 | 102 | ```
|
54 |
| -LD_LIBRARY_PATH=/data/local/tmp/coreclr/lib ./runpaltests.sh /data/local/tmp/coreclr/ |
| 103 | +<repo-root>artifacts/bin/AndroidSampleApp/<x64|arm64>/<Debug|Release>/android-<x64|arm64>/Bundle/bin/HelloAndroid.apk |
55 | 104 | ```
|
56 | 105 |
|
57 |
| -Debugging coreclr on Android |
58 |
| ----------------------------- |
| 106 | +### Running HelloAndroid sample on an emulator |
59 | 107 |
|
60 |
| -You can debug coreclr on Android using a remote lldb server which you run on your Android device. |
| 108 | +To run the sample on an emulator, the emulator first needs to be up and running. |
61 | 109 |
|
62 |
| -First, push the lldb server to Android: |
| 110 | +Creating an emulator (ADV - Android Virtual Device) can be achieved through [Android Studio - Device Manager](https://developer.android.com/studio/run/managing-avds). |
63 | 111 |
|
| 112 | +After its creation, the emulator needs to be booted up and running, so that we can run the `HelloAndroid` sample on it via: |
64 | 113 | ```
|
65 |
| -adb push cross/android/lldb/2.2/android/arm64-v8a/lldb-server /data/local/tmp/ |
| 114 | +make BUILD_CONFIG=<Debug|Release> TARGET_ARCH=<x64|arm64> RUNTIME_FLAVOR=CoreCLR DEPLOY_AND_RUN=true run -C src/mono/sample/Android |
66 | 115 | ```
|
67 | 116 |
|
68 |
| -Then, launch the lldb server on the Android device. Open a shell using `adb shell` and run: |
| 117 | + |
| 118 | +> [!NOTE] |
| 119 | +> Emulators can be also started from the terminal via: |
| 120 | +> ``` |
| 121 | +> $ANDROID_SDK_ROOT/emulator/emulator -avd <emulator-name> |
| 122 | +> ``` |
| 123 | +
|
| 124 | +#### WSL2 |
| 125 | +
|
| 126 | +The app can be run on an emulator running on the Windows host. |
| 127 | +1. Install Android Studio on the Windows host (same versions as in [prerequisites](#prerequisite)) |
| 128 | +2. In Windows, create and start an emulator |
| 129 | +3. In WSL, swap the `adb` from the Android SDK in WSL2 with that from Windows |
| 130 | + - `mv $ANDROID_SDK_ROOT/platform-tools/adb $ANDROID_SDK_ROOT/platform-tools/adb-orig` |
| 131 | + - `ln -s /mnt/<path-to-adb-on-host> $ANDROID_SDK_ROOT/platform-tools/adb` |
| 132 | +4. In WSL, Make xharness use the `adb` corresponding to the Windows host: |
| 133 | + - `export ADB_EXE_PATH=$ANDROID_SDK_ROOT/platform-tools/adb` |
| 134 | +5. In WSL, run the `make` command as [above](#running-helloandroid-sample-on-an-emulator) |
| 135 | +
|
| 136 | +### Building and running functional tests on an emulator |
| 137 | +
|
| 138 | +Similarly to the `HelloAndroid` sample, it is possible to build and run a functional test on Android with CoreCLR on an emulator. |
| 139 | +
|
| 140 | +To build and run a functional test on Android with CoreCLR, run the following command from `<repo_root>`: |
69 | 141 |
|
70 | 142 | ```
|
71 |
| -adb shell |
72 |
| -cd /data/local/tmp |
73 |
| -./lldb-server platform --listen *:1234 |
| 143 | +./dotnet.sh build -c Release src/tests/FunctionalTests/Android/Device_Emulator/JIT/Android.Device_Emulator.JIT.Test.csproj /p:TargetOS=android /p:TargetArchitecture=arm64 /t:Test /p:RuntimeFlavor=coreclr |
74 | 144 | ```
|
75 | 145 |
|
76 |
| -After that, you'll need to forward port 1234 from your Android device to your PC: |
| 146 | +> [!NOTE] |
| 147 | +> Similarly to the `HelloAndroid` sample the emulator needs to be up and running. |
| 148 | +
|
| 149 | +### Useful make commands |
| 150 | +
|
| 151 | +For convenience it is possible to run a single make command which builds all required dependencies, the app and runs it: |
77 | 152 | ```
|
78 |
| -adb forward tcp:1234 tcp:1234 |
| 153 | +make BUILD_CONFIG=<Debug|Release> TARGET_ARCH=<x64|arm64> RUNTIME_FLAVOR=CoreCLR DEPLOY_AND_RUN=true all -C src/mono/sample/Android |
79 | 154 | ```
|
80 | 155 |
|
81 |
| -Finally, install lldb on your PC and connect to the debug server running on your Android device: |
| 156 | +## Debugging the runtime and the sample app |
82 | 157 |
|
83 |
| -``` |
84 |
| -lldb-3.9 |
85 |
| -(lldb) platform select remote-android |
86 |
| - Platform: remote-android |
87 |
| - Connected: no |
88 |
| -(lldb) platform connect connect://localhost:1234 |
89 |
| - Platform: remote-android |
90 |
| - Triple: aarch64-*-linux-android |
91 |
| -OS Version: 23.0.0 (3.10.84-perf-gf38969a) |
92 |
| - Kernel: #1 SMP PREEMPT Fri Sep 16 11:29:29 2016 |
93 |
| - Hostname: localhost |
94 |
| - Connected: yes |
95 |
| -WorkingDir: /data/local/tmp |
| 158 | +Managed debugging is currently not supported, but we can debug: |
| 159 | +- Java portion of the sample app |
| 160 | +- Native code for the CoreCLR host and the runtime it self |
| 161 | +
|
| 162 | +This can be achieved in `Android Studio` via `Profile or Debug APK`. |
| 163 | +
|
| 164 | +### Steps |
| 165 | +
|
| 166 | +1. Build the runtime and `HelloAndroid` sample app in `Debug` configuration targeting `arm64` target architecture. |
| 167 | +2. Rename the debug symbols file of the runtime library from `libcoreclr.so.dbg` into `libcoreclr.so.so`, the file is located at: `<repo_root>/artifacts/bin/AndroidSampleApp/arm64/Debug/android-arm64/publish/libcoreclr.so.dbg` |
| 168 | +3. Open Android Studio and select `Profile or Debug APK` project. |
| 169 | +4. Find and select the desired `.apk` file (example: `<repo_root>/artifacts/bin/AndroidSampleApp/arm64/Debug/android-arm64/Bundle/bin/HelloAndroid.apk`) |
| 170 | +5. In the project pane, expand `HelloAndroid->cpp->libcoreclr` and double-click `libcoreclr.so` |
| 171 | + |
| 172 | +6. From the `Debug Symbols` pane on the right, select `Add` |
| 173 | +7. Navigate to the renamed file from step 2. and select it `<repo_root>/artifacts/bin/AndroidSampleApp/arm64/Debug/android-arm64/publish/libcoreclr.so.so` |
| 174 | +8. Once loaded it will show all the source files under `HelloAndroid->cpp->libcoreclr` |
| 175 | + |
| 176 | +9. Find the `exports.cpp` and set a breakpoint in `coreclr_initialize` function and launch the debug session |
| 177 | + |
96 | 178 |
|
97 |
| -(lldb) target create coreclr/pal/tests/palsuite/file_io/CopyFileA/test4/paltest_copyfilea_test4 |
98 |
| -(lldb) env LD_LIBRARY_PATH=/data/local/tmp/coreclr/lib |
99 |
| -(lldb) run |
| 179 | +> [!NOTE] |
| 180 | +> Steps 5) through 8) can be omitted if the runtime is built without stripping debug symbols to a separate file (e.g., `libcoreclr.so.dbg`). |
| 181 | +> This can be achieved by including `-keepnativesymbols true` option when building the runtime, e.g.,: |
| 182 | +> ``` |
| 183 | +> ./build.sh clr.runtime+clr.alljits+clr.corelib+clr.nativecorelib+clr.tools+clr.packages+libs -os android -arch <x64|arm64> -c Debug -keepnativesymbols true |
| 184 | +> ``` |
| 185 | +
|
| 186 | +## See also |
| 187 | +
|
| 188 | +Similar instructions for debugging Android apps with Mono runtime can be found [here](../../debugging/mono/android-debugging.md). |
| 189 | +
|
| 190 | +## Troubleshooting |
| 191 | +
|
| 192 | +### Android samples or functional tests fail to build |
| 193 | +
|
| 194 | +If multiple JDKs are installed on your system, you may encounter the following error: |
| 195 | +
|
| 196 | +``` |
| 197 | +`src/mono/msbuild/android/build/AndroidBuild.targets(237,5): error MSB4018: java.lang.NullPointerException: Cannot invoke String.length() because <parameter1> is null |
100 | 198 | ```
|
| 199 | +
|
| 200 | +when building the Android samples or functional tests. |
| 201 | +
|
| 202 | +To resolve this: |
| 203 | +1. Remove older JDK versions |
| 204 | +2. Install [OpenJDK 23](https://openjdk.org/projects/jdk/23/) |
| 205 | +3. Make sure OpenJDK 23 binaries are added to the path. |
| 206 | + - On Unix system this can be verifed via: |
| 207 | + ``` |
| 208 | + $> java -version |
| 209 | + openjdk version "23.0.1" 2024-10-15 |
| 210 | + OpenJDK Runtime Environment Homebrew (build 23.0.1) |
| 211 | + OpenJDK 64-Bit Server VM Homebrew (build 23.0.1, mixed mode, sharing) |
| 212 | + ``` |
0 commit comments