1Android 2======= 3 4Mesa hardware drivers can be built for Android one of two ways: built 5into the Android OS using the Android.mk build system on older versions 6of Android, or out-of-tree using the Meson build system and the 7Android NDK. 8 9The Android.mk build system has proven to be hard to maintain, as one 10needs a built Android tree to build against, and it has never been 11tested in CI. The meson build system flow is frequently used by 12Chrome OS developers for building and testing Android drivers. 13 14Building using the Android NDK 15------------------------------ 16 17Download and install the NDK using whatever method you normally would. 18Then, create your meson cross file to use it, something like this 19``~/.local/share/meson/cross/android-aarch64`` file:: 20 21 [binaries] 22 ar = 'NDKDIR/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android-ar' 23 c = ['ccache', 'NDKDIR/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android29-clang'] 24 cpp = ['ccache', 'NDKDIR/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android29-clang++', '-fno-exceptions', '-fno-unwind-tables', '-fno-asynchronous-unwind-tables', '-static-libstdc++'] 25 c_ld = 'lld' 26 cpp_ld = 'lld' 27 strip = 'NDKDIR/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android-strip' 28 # Android doesn't come with a pkg-config, but we need one for meson to be happy not 29 # finding all the optional deps it looks for. Use system pkg-config pointing at a 30 # directory we get to populate with any .pc files we want to add for Android 31 pkgconfig = ['env', 'PKG_CONFIG_LIBDIR=NDKDIR/pkgconfig', '/usr/bin/pkg-config'] 32 33 [host_machine] 34 system = 'linux' 35 cpu_family = 'arm' 36 cpu = 'armv8' 37 endian = 'little' 38 39Now, use that cross file for your Android build directory (as in this 40one cross-compiling the turnip driver for a stock Pixel phone) 41 42.. code-block:: console 43 44 meson build-android-aarch64 \ 45 --cross-file android-aarch64 \ 46 -Dplatforms=android \ 47 -Dplatform-sdk-version=26 \ 48 -Dandroid-stub=true \ 49 -Dgallium-drivers= \ 50 -Dvulkan-drivers=freedreno \ 51 -Dfreedreno-kgsl=true 52 ninja -C build-android-aarch64 53 54Replacing Android drivers on stock Android 55------------------------------------------ 56 57The vendor partition with the drivers is normally mounted from a 58read-only disk image on ``/vendor``. To be able to replace them for 59driver development, we need to unlock the device and remount 60``/vendor`` read/write. 61 62.. code-block:: console 63 64 adb disable-verity 65 adb reboot 66 adb remount -R 67 68Now you can replace drivers as in: 69 70.. code-block:: console 71 72 adb push build-android-aarch64/src/freedreno/vulkan/libvulkan_freedreno.so /vendor/lib64/hw/vulkan.sdm710.so 73 74Note this command doesn't quite work because libvulkan wants the 75SONAME to match. For now, in turnip we have been using a hack to the 76meson.build to change the SONAME. 77 78Replacing Android drivers on Chrome OS 79-------------------------------------- 80 81Chrome OS's ARC++ is an Android container with hardware drivers inside 82of it. The vendor partition with the drivers is normally mounted from 83a read-only squashfs image on disk. For doing rapid driver 84development, you don't want to regenerate that image. So, we'll take 85the existing squashfs image, copy it out on the host, and then use a 86bind mount instead of a loopback mount so we can update our drivers 87using scp from outside the container. 88 89On your device, you'll want to make ``/`` read-write. ssh in as root 90and run: 91 92.. code-block:: console 93 94 crossystem dev_boot_signed_only=0 95 /usr/share/vboot/bin/make_dev_ssd.sh --remove_rootfs_verification --partitions 4 96 reboot 97 98Then, we'll switch Android from using an image for ``/vendor`` to using a 99bind-mount from a directory we control. 100 101.. code-block:: console 102 103 cd /opt/google/containers/android/ 104 mkdir vendor-ro 105 mount -o loop vendor.raw.img vendor-ro 106 cp -a vendor-ro vendor-rw 107 emacs config.json 108 109In the ``config.json``, you want to find the block for ``/vendor`` and 110change it to:: 111 112 { 113 "destination": "/vendor", 114 "type": "bind", 115 "source": "/opt/google/containers/android/vendor-rw", 116 "options": [ 117 "bind", 118 "rw" 119 ] 120 }, 121 122Now, restart the UI to do a full reload: 123 124.. code-block:: console 125 126 restart ui 127 128At this point, your android container is restarted with your new 129bind-mount ``/vendor``, and if you use ``android-sh`` to shell into it 130then the ``mount`` command should show:: 131 132 /dev/root on /vendor type ext2 (rw,seclabel,relatime) 133 134Now, replacing your DRI driver with a new one built for Android should 135be a matter of: 136 137.. code-block:: console 138 139 scp msm_dri.so $HOST:/opt/google/containers/android/vendor-rw/lib64/dri/ 140 141You can do your build of your DRI driver using ``emerge-$BOARD 142arc-mesa-freedreno`` (for example) if you have a source tree with 143ARC++, but it should also be possible to build using the NDK as 144described above. There are currently rough edges with this, for 145example the build will require that you have your arc-libdrm build 146available to the NDK, assuming you're building anything but the 147freedreno Vulkan driver for KGSL. You can mostly put things in place 148with: 149 150.. code-block:: console 151 152 scp $HOST:/opt/google/containers/android/vendor-rw/lib64/libdrm.so \ 153 NDKDIR/sysroot/usr/lib/aarch64-linux-android/lib/ 154 155 ln -s \ 156 /usr/include/xf86drm.h \ 157 /usr/include/libsync.h \ 158 /usr/include/libdrm \ 159 NDKDIR/sysroot/usr/include/ 160 161It seems that new invocations of an application will often reload the 162DRI driver, but depending on the component you're working on you may 163find you need to reload the whole Android container. To do so without 164having to log in to Chrome again every time, you can just kill the 165container and let it restart: 166 167.. code-block:: console 168 169 kill $(cat /run/containers/android-run_oci/container.pid ) 170