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