The stub libbinder_ndk.so
in ndk's sysroot hides some apis, so that we cannot link our libbiner_rs
to it. However, we can rebuild a stub so to make linker happy. The stub source is generated from symbols.txt, whose contents are extracted from prebuilt libbinder_ndk.so
from aosp-mainline.
The libbinder_ndk.so is introduced in api-29, you need to compile it with specified target api level. The compilation won't fail if api is lower than 29, because we build the dynamic library ourselves.
For each Android target you wish to build for you must e.g.
rustup target add \
aarch64-linux-android \
armv7-linux-androideabi \
x86_64-linux-android \
i686-linux-android
cargo-ndk
simplifies the process of building libraries and binaries
for Android targets.
-
Install Android Studio
-
Install the NDK from within Android Studio
-
Install
cargo-ndk
with:
cargo install cargo-ndk
We use cargo ndk
to build the stub so, ANDROID_NDK_HOME
must be set in your env !
If you follow the steps below in Generate Rust code from AIDL from the AOSP
you will get a libbinder_ndk.so
build 'for free' for your target architecture.
Copy that libbinder_ndk.so
from where it's built in the aosp root to where
it should belong in the path to your NDK install.
In my case I copied it from:
<aosp-root>/out/target/product/generic_x86_64/system/lib64/libbinder_ndk.so
to
~/Android/Sdk/ndk/<version-of-ndk>/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/lib/x86_64-linux-android/29/libbinder_ndk.so
since I was going to compile with platform API level 29 and for x86_64.
sys/src/include_*
from platform/frameworks/native/libs/binder/ndk
-
Build
cargo ndk -t arm64-v8a --platform=29 --bindgen build
-
Push file to phone
adb push target/aarch64-linux-android/debug/binder-example /data/local/tmp
-
Run 2 adb shell
Run server:
adb shell su -c /data/local/tmp/binder-example server
Run client:
adb shell su -c /data/local/tmp/binder-example client
-
Build
cargo ndk -t arm64-v8a --platform=29 --bindgen build
-
Push files to phone
adb push target/aarch64-linux-android/debug/binder-tests /data/local/tmp
-
Build unittest binary
cargo ndk -t arm64-v8a --platform=29 --bindgen test --bin binder-tests --no-run
-
Push files to phone
adb push target/aarch64-linux-android/debug/deps/binder_tests-acf830ec15b8864e /data/local/tmp
-
Run test
adb shell cd /data/local/tmp/ && su -c ./binder_tests-acf830ec15b8864e
if you see error like this
CANNOT LINK EXECUTABLE "/data/local/tmp/binder_tests-acf830ec15b8864e": cannot locate symbol "AIBinder_DeathRecipient_setOnUnlinked" referenced by "/data/local/tmp/binder_tests-acf830ec15b8864e"...
This is because your android version is too low, the source is from android-mainline. You can try in avd, with Android U
- Create AIDL + any
UnstructuredParcelable
you want to use in your AIDL interface- Reference
unstructured_parcelable_example/aosp_module_to_generate_aidl
- Reference
Note the structure:
my_simple_parcelable_service/
Android.bp
: Soong build fileaidl/
Android.bp
: Soong build filecom/example/mysimpleparcelableservice
IMySimpleParcelableService.aidl
: The service interface, note we are includingMySimpleParcelable
as a return parameterMySimpleParcelable.aidl
: Essentially a bit of a "wrapper" which points to the actual definition of the UnstructuredParcelable in therust
folder, see belowrust/
my_simple_parcelable.rs
: Note that we have to impl theUnstructuredParcelable
trait.
src/
lib.rs
: Implementation of the service. We only need to impl it because Soong will not let us make the AIDL directly. Note that this is not actually used at all.
- Use Soong to build. You need to put the above folder under
<aosp-root>/external/rust/<your-aidl-lib-folder>
- As per normal when building out of the AOSP, you'll need to
choose your target architecture, so do the following steps first
from the aosp root:
source build/envsetup.sh
lunch <your-target-choice>
- Recall you can type
lunch
by itself to get a listing of available targets
- Recall you can type
- As per normal when building out of the AOSP, you'll need to
choose your target architecture, so do the following steps first
from the aosp root:
You may then proceed with building:
m libmysimpleparcelableservice
Expected output
============================================
PLATFORM_VERSION_CODENAME=VanillaIceCream
PLATFORM_VERSION=VanillaIceCream
PRODUCT_INCLUDE_TAGS=com.android.mainline mainline_module_prebuilt_nightly
TARGET_PRODUCT=aosp_x86_64
TARGET_BUILD_VARIANT=eng
TARGET_ARCH=x86_64
TARGET_ARCH_VARIANT=x86_64
TARGET_2ND_ARCH=x86
TARGET_2ND_ARCH_VARIANT=x86_64
HOST_OS=linux
HOST_OS_EXTRA=Linux-5.15.0-79-generic-x86_64-Ubuntu-20.04.6-LTS
HOST_CROSS_OS=windows
BUILD_ID=MAIN
OUT_DIR=out
============================================
[ 22% 8/36 1m15s remaining] AIDL Rust external/rust/my_simple_parcelable_service/aidl/com/example/mysimp
Compiling IDL...
GenerateRust: out/soong/.intermediates/external/rust/my_simple_parcelable_service/aidl/com.example.mysim
pleparcelableservice-rust-source/gen/com/example/mysimpleparcelableservice/IMySimpleParcelableService.rs
[100% 36/36 1m14s remaining] Install: out/target/product/generic_x86_64/system/lib64/libmysimpleparcelab
#### build completed successfully (02:19 (mm:ss)) ####
-
Navigate to Soong intermediate build folder and scoop up generated Rust code.
- In this case it was located at:
<aosp-root>/out/soong/.intermediates/external/rust/my_simple_parcelable_service/aidl/com.example.mysimpleparcelableservice-rust-source/gen/com/example/mysimpleparcelableservice/IMySimpleParcelableService.rs
- In this case it was located at:
-
Assemble the pieces in your Rust project
- Copy in your generated Rust source for the interface from step 3
- Copy in the Rust source of your
UnstructuredParcelable
s from step 1
-
Build
cargo ndk -t x86_64 --platform=29 --bindgen build
- Remaining steps to copy / run example same as above