Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding 2 new features: interop with Java Binder through JNI & UnstructureParcelable (i.e. custom parcelables) #7

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
Open
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
target
.DS_Store
.DS_Store

.idea/
115 changes: 103 additions & 12 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ members = [
"binder_tokio",
"binder_ndk_sys",
"example",
"unstructured_parcelable_example",
"tests",
]

Expand Down
138 changes: 135 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,57 @@

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.

The libbinder_ndk.so is introduced in api-29, you need to compile it with specified target api level. The compilation won't failed if api is lower than 29, because we build the dynamic library on ourselves.
## Adding Android targets via rustup

For each Android target you wish to build for you must e.g.

We use ndk-build to build the stub so, `ANDROID_NDK_HOME` must be set in your env !
```bash
rustup target add \
aarch64-linux-android \
armv7-linux-androideabi \
x86_64-linux-android \
i686-linux-android
```

## Building using the `cargo-ndk` tooling

`cargo-ndk` simplifies the process of building libraries and binaries
for Android targets.

1. Install Android Studio

2. Install the NDK from within Android Studio

3. Install `cargo-ndk` with:

```bash
cargo install cargo-ndk
```

We use `cargo ndk` to build the stub so, `ANDROID_NDK_HOME` must be set in your env !

## Building your own `libbinder_ndk.so` from the AOSP

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.

## Side note on where the sources are from

> `sys/src/include_*` from [platform/frameworks/native/libs/binder/ndk](https://android.googlesource.com/platform/frameworks/native/+/refs/heads/master/libs/binder/ndk/)

Expand Down Expand Up @@ -80,4 +125,91 @@ We use ndk-build to build the stub so, `ANDROID_NDK_HOME` must be set in your en
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
This is because your android version is too low, the source is from android-mainline. You can try in avd, with Android U

## Using AIDLs with UnstructuredParcelable

### Generate Rust code from AIDL from the AOSP

1. Create AIDL + any `UnstructuredParcelable` you want to use
in your AIDL interface
* Reference `unstructured_parcelable_example/aosp_module_to_generate_aidl`

Note the structure:
* `my_simple_parcelable_service/`
* `Android.bp`: Soong build file
* `aidl/`
* `Android.bp`: Soong build file
* `com/example/mysimpleparcelableservice`
* `IMySimpleParcelableService.aidl`: The service interface, note
we are including `MySimpleParcelable` as a return parameter
* `MySimpleParcelable.aidl`: Essentially a bit of a "wrapper"
which points to the actual definition of the
UnstructuredParcelable in the `rust` folder, see below
* `rust/`
* `my_simple_parcelable.rs`: Note that we have to impl
the `UnstructuredParcelable` 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.

2. 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

You may then proceed with building:

```bash
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)) ####
```

3. 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`

4. 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

5. Build

```bash
cargo ndk -t x86_64 --platform=29 --bindgen build
```

6. Remaining steps to copy / run example same as above
2 changes: 1 addition & 1 deletion binder/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[package]
name = "binder_ndk"
name = "binder"

edition.workspace = true
version.workspace = true
Expand Down
Loading