• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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