rust-mobile / android-activity

Glue for building Rust applications on Android with NativeActivity or GameActivity
251 stars 49 forks source link

Support for exposing services #53

Open s1341 opened 3 years ago

s1341 commented 3 years ago

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?

dvc94ch commented 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

s1341 commented 3 years ago

Thanks for looking into this.

I'm going to close the issue for now, as I don't see a way forward.

canndrew commented 3 years ago

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

dvc94ch commented 3 years ago

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.

MarijnS95 commented 3 years ago

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.

dvc94ch commented 3 years ago

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.

MarijnS95 commented 3 years ago

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

dvc94ch commented 3 years ago

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.

dvc94ch commented 3 years ago

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.

MarijnS95 commented 3 years ago

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

dvc94ch commented 2 years ago

@s1341 I see you wrote a rust binder implementation interfacing directly with /dev/binder. does this actually work without rooting?

s1341 commented 2 years ago

You cannot register a service without root, unfortunately. But you can talk to existing services/content-providers/etc.

MarijnS95 commented 2 years ago

Doesn't the NDK expose a Binder API nowadays? https://developer.android.com/ndk/reference/group/ndk-binder

dvc94ch commented 2 years ago

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?

MarijnS95 commented 2 years ago

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!