Open s1341 opened 3 years ago
looked into this a bit. unlike the NativeActivity
there is no NativeService
. there is a libbinder.so
that provides what is needed, but it seems that that is only available for oems and not application developers. the libbinder_ndk.so
that is available to app developers seems to lack essential functionality like AServiceManager_getService
. Not sure what libbinder_ndk.so
is useful for exactly. for these reasons I think cargo-apk
won't work for services and you need to stick with java/gradle and loading a dynamic library. cc @wngr
Thanks for looking into this.
I'm going to close the issue for now, as I don't see a way forward.
Hi, I'm a complete noob to this stuff and trying to write my first android app in rust, so sorry if this is a dumb question. Would it be possible to let users define services and have cargo apk
generate a small java shim for each service which it links to from the manifest?
I was hoping to avoid having to deal with java and android studio, and it's cool that this project allows me to do that for the simple test app that I've written, but now I want to run my app as a background service. Since ordinary non-OEM developers are allowed to define services, and since cargo apk
is already generating a bunch of stuff to wrap my rust program into an android package, it seems like it should be possible to have cargo apk
generate whatever more stuff is necessary to define services and have the entry points of the service just call into my rust code, no? Or is this out-of-scope for this project or otherwise impossible for reasons explained above?
(Again, sorry for the noise if I'm being dumb. I've only been learning android for an entire hour.)
It may be possible to invent a NativeService. I guess the first step would be to copy the NativeActivity (from the Android sources) and try to build an APK using the custom NativeActivity instead of the stock one. Then we could discuss extending cargo-apk/ndk-glue/etc with some service callbacks.
For the record android-ndk-rs doesn't generate anything besides AndroidManifest.xml. The rest is C bindings (and safe wrappers) around the NDK, toolchain discovery and setting up the compiler/linker to target Android.
Since the NDK does not provide any API to host native services this sounds like a separate project/crate that does all the heavy Java lifting through JNI.
I agree with you that any jni stuff is out of scope (last part of the diagram below). But this is about the entry point:
java NativeActivity -> rust -> java libraries via jni
I think this might be in scope for cargo-apk
as it requires support to compile a bit of java using javac and somehow link it agains android.jar
and include it in the apk. Also the generated AndroidManifest.xml
would need to support using it as an entry point.
@dvc94ch Ah, right, that sounds okay I guess. We have much better support for custom Manifest entries in Cargo.toml
now so it wouldn't be too hard to define ones' custom <activity>
in there now.
That said I do wonder if you can get away with implementing this in pure Rust through the JNI, instead of going through Java and javac
like how NativeActivity
is defined? Though, that's something for the implementor to investigate and decide on.
That isn't possible, all apks are java applications with possibly native dynamic libraries. In addition there is a default java activity called NativeActivity
that loads a dynamic library from an apk and calls some callbacks in it. In the AndroidManifest we declare that it should be loaded using the NativeActivity, and this works as long as the NativeActivity is sufficient. In the case of services or background tasks there is no support for loading native code directly, so we'd need to customize the NativeActivity to support more use cases.
I guess once someone gives it a go and opens a PR and there is a concrete proposal we can discuss it further. I think we will have to create a custom rust loader in java and support it in ndk-glue and cargo-apk.
@dvc94ch Indeed NativeActivity
(android.app.Activity
subclass) is implemented in Java which loads the shared object and "forwards" callbacks to native functions. It should be possible to create a Java class from Rust that does the same for android.app.Service
, but I have no idea how to teach ART and friends to retrieve and instantiate a class type from a native function instead of loading it from classes.dex
(which is why NativeActivity
exists in the first place). Seems like that is not possible unfortunately.
@s1341 I see you wrote a rust binder implementation interfacing directly with /dev/binder. does this actually work without rooting?
You cannot register a service without root, unfortunately. But you can talk to existing services/content-providers/etc.
Doesn't the NDK expose a Binder API nowadays? https://developer.android.com/ndk/reference/group/ndk-binder
I'm a bit confused. android.jar seems to be mostly thin wrappers around aidl generated code. aidl has a c++ and rust backend. why doesn't the ndk generate support for all the services? Can we use the rust aidl backend to generate bindings that work?
Isn't that Rust backend fairly new? I'm not surprised/confused why our ndk
doesn't use that yet :)
But I'm all in favour of adding a new ndk-aidl
crate of some sorts!
It doesn't seem like there is currently support for exposing services from an application.
I'd like to add this feature... How do I wire up the service from the 'java' to a function?