Native executable and JNI

777 views
Skip to first unread message

Ryan

unread,
Aug 3, 2011, 5:48:55 PM8/3/11
to android-ndk
Hi,

I have an NDK executable written in C and built with "include $
(BUILD_EXECUTABLE)". It works well, but I need access to Android
API's in order to test for network connectivity, etc. I have tried
writing a JNI bridge. This was a lot of work, but in the end I can
access my Java class. The general idea is to use the
ConnectivityManager to check if NetworkInfo.isConnected() and return
the result back to the C code.

Of course I can't call Context.getSystemService() without a Context.
And since my VM was launched from Native C rather than from Zygote or
whatever really happens under the hood, I don't have ready access to a
Context. This is ye olde "How can I get a static Context???"
problem.

Does anybody see any way around this? I don't know enough about what
happens behind the scenes to know if this is a complete dead end or
whether there is some other avenue I can try.

NB:
- Yes, I really do have a good business rational for doing this.
- No, for many business and technical reasons I cannot port my C
application to Java.

Thanks,
Ryan

David Turner

unread,
Aug 4, 2011, 4:03:38 AM8/4/11
to andro...@googlegroups.com
On Wed, Aug 3, 2011 at 11:48 PM, Ryan <ryan.jam...@gmail.com> wrote:
Hi,

I have an NDK executable written in C and built with "include $
(BUILD_EXECUTABLE)".  It works well, but I need access to Android
API's in order to test for network connectivity, etc.  I have tried
writing a JNI bridge.  This was a lot of work, but in the end I can
access my Java class.  The general idea is to use the
ConnectivityManager to check if NetworkInfo.isConnected() and return
the result back to the C code.

Of course I can't call Context.getSystemService() without a Context.
And since my VM was launched from Native C rather than from Zygote or
whatever really happens under the hood, I don't have ready access to a
Context.  This is ye olde "How can I get a static Context???"
problem.

Does anybody see any way around this?  I don't know enough about what
happens behind the scenes to know if this is a complete dead end or
whether there is some other avenue I can try.

In a nutshell you can't: an executable is not an Android application and hence doesn't have a Context.

NB:
- Yes, I really do have a good business rational for doing this.
- No, for many business and technical reasons I cannot port my C
application to Java.


 
Thanks,
Ryan

--
You received this message because you are subscribed to the Google Groups "android-ndk" group.
To post to this group, send email to andro...@googlegroups.com.
To unsubscribe from this group, send email to android-ndk...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/android-ndk?hl=en.


Ryan

unread,
Aug 4, 2011, 11:49:55 AM8/4/11
to andro...@googlegroups.com
Thanks for your answer Digit.  I suspected this was the case, but it isn't exactly spelled out.  This somewhat limits the usefulness of JNI.

Does anybody know of any other mechanism whereby an executable can trigger something to happen in Android space?  Maybe via Intents or Bound Services?

Thanks,
Ryan



Chris Stratton

unread,
Aug 4, 2011, 12:34:12 PM8/4/11
to andro...@googlegroups.com
On Wednesday, August 3, 2011 5:48:55 PM UTC-4, Ryan wrote:

I have an NDK executable written in C and built with "include $
(BUILD_EXECUTABLE)".  It works well, but I need access to Android
API's in order to test for network connectivity, etc.  I have tried
writing a JNI bridge.  This was a lot of work, but in the end I can
access my Java class.

Well, congratulations on accomplishing something technically interesting.  But why do you have to do it this way?

I can see why you would want to - cleanliness of implementation and all, but it's not really apparent how a process not forked off zygote can register through binder to get the kind of recognition as a legitimate client by the system server; ordinarily it's automatically granted this rather than requesting it.

Couldn't you let android create your process in the ordinary fashion and then run your native code in its own thread, mostly ignorant of the fact that it has a dalvik vm and binder worker threads and all sharing its process space, up until the time when you actually need to use those to proxy things to the framework for you?  Yes, this seems wasteful (though much of the memory should be shared maps) but it's unfortunately the only model supported.
 
 The general idea is to use the
ConnectivityManager to check if NetworkInfo.isConnected() and return
the result back to the C code.

If that's all you want to do, perhaps there are other methods - things in /proc/net for example.  These wouldn't be officially stable APIs, but then you seem to be wanting to develop for what android devices could be rather than what they were intended to be.

Ryan

unread,
Aug 4, 2011, 2:07:22 PM8/4/11
to andro...@googlegroups.com
D'oh.  Google Groups ate my reply.  Here's a repost.


Well, congratulations on accomplishing something technically interesting.  But why do you have to do it this way?

I am trying to reduce the memory footprint of an application that will be installed by the handset manufacturer (i.e. it is not an end-user application and it interacts with the device hardware on some level).  This application is almost always idle, except for a few brief periods where it does something useful.  Most of the work can be done natively, but some of it needs the Android API's.  Some of this is just being polite.  Just because I can open a socket and download a bunch of data doesn't mean I should (what if the user is roaming?).  Some of this is to access the IMEI, etc. which AFAIK is only accessible through the Android API's.
 

Couldn't you let android create your process in the ordinary fashion and then run your native code in its own thread, mostly ignorant of the fact that it has a dalvik vm and binder worker threads and all sharing its process space, up until the time when you actually need to use those to proxy things to the framework for you?  Yes, this seems wasteful (though much of the memory should be shared maps) but it's unfortunately the only model supported.

This is more or less the same proxy model that we currently use.  I have some concerns though.  I don't like the huge increase in memory footprint (although as you mention much of this should be shared maps).  There is also no guarantee that the process will exist when I need it.  When device memory gets low, it seems like a good candidate to be killed, since it has no UI and no user process that has UI depends on it.

Thanks for your insights.

Cheers,
Ryan
 

Chris Stratton

unread,
Aug 4, 2011, 2:37:27 PM8/4/11
to andro...@googlegroups.com
On Thursday, August 4, 2011 2:07:22 PM UTC-4, Ryan wrote:

I am trying to reduce the memory footprint of an application that will be installed by the handset manufacturer (i.e. it is not an end-user application and it interacts with the device hardware on some level).  This application is almost always idle, except for a few brief periods where it does something useful. 

Since you have access to the vendor's system keys, there may be a way to run this within the system server process.

David Turner

unread,
Aug 4, 2011, 2:52:15 PM8/4/11
to andro...@googlegroups.com
For what is worth, what you're describing should better be implemented by  a daemon started/controlled through init.rc, which communicates with a service running inside the "system" VM process (see frameworks/base/services/java/com/android/server/ for existing ones). This definitely doesn't look like an "application".

Thanks for your insights.

Cheers,
Ryan
 

--
You received this message because you are subscribed to the Google Groups "android-ndk" group.
To view this discussion on the web visit https://groups.google.com/d/msg/android-ndk/-/JCEEQMUUNoEJ.

Ryan

unread,
Aug 4, 2011, 4:44:40 PM8/4/11
to andro...@googlegroups.com
 
For what is worth, what you're describing should better be implemented by  a daemon started/controlled through init.rc, which communicates with a service running inside the "system" VM process (see frameworks/base/services/java/com/android/server/ for existing ones). This definitely doesn't look like an "application".


Very interesting.  Just to clarify, when you say communicate, do you mean using pipes/other IPC or is there some other Android-esque way of doing this that I don't know about?

Thanks,
Ryan
 

Ryan

unread,
Aug 4, 2011, 8:15:19 PM8/4/11
to andro...@googlegroups.com
Sorry to answer my own post, but now I think I see it.  NativeDaemonConnector on the Java side and FrameworkListener on the native side.  The service should be started by the SystemServer and then connect to the native daemon via NativeDaemonConnector.  The daemon can then trigger Java events (i.e. INativeDaemonConnectorCallbacks.onEvent()) by calling SocketClient::sendMsg(), though the "normal" case is probably the other way around.

It's a bit roundabout, but I think it would work.  If I understand things correctly, there is no JNI work here, which is nice.

David Turner

unread,
Aug 5, 2011, 2:52:43 AM8/5/11
to andro...@googlegroups.com
On Thu, Aug 4, 2011 at 10:44 PM, Ryan <ryan.jam...@gmail.com> wrote:
 
For what is worth, what you're describing should better be implemented by  a daemon started/controlled through init.rc, which communicates with a service running inside the "system" VM process (see frameworks/base/services/java/com/android/server/ for existing ones). This definitely doesn't look like an "application".


Very interesting.  Just to clarify, when you say communicate, do you mean using pipes/other IPC or is there some other Android-esque way of doing this that I don't know about?

Yes, just using a Unix domain socket should be enough. This is actually already used by many parts of the system (no need for Binder, etc...). One example is the Radio Interface Layer (RIL) service running in the VM that communicates with the "rild" daemon.

The nice thing about Android is that you can specify the your need the socket right in init.rc. The pipe will be created directly by init, with the right ownership/permissions, before launching the native service process (which can retrieve a fd to it at startup with android_get_control_socket(), see the comments in system/core/include/cutils/socket.h).

 
Thanks,
Ryan
 

--
You received this message because you are subscribed to the Google Groups "android-ndk" group.
To view this discussion on the web visit https://groups.google.com/d/msg/android-ndk/-/yebxpVL4WP4J.

AppCoder

unread,
Aug 4, 2011, 9:01:09 AM8/4/11
to android-ndk

> Does anybody see any way around this?  I don't know enough about what
> happens behind the scenes to know if this is a complete dead end or
> whether there is some other avenue I can try.

You can shell out with exec/system and throw an intent with
"am start <bla bla bla>" and have a listener on a socket or
named pipe, or watch shared memory, or tests for a pipe, and
have a java receiver that connects to the listener and tells
you what you want (it may even include jni code to connect
in a non-java way.)

If you don't like "am start" (or, as in this case, you are
looking for something that can be seen by intents you register
for) you could just do something that is a java connectivity
listener that writes to a file somewhere that your C code can
read and you can go look for the result there.

Dan

AppCoder

unread,
Aug 5, 2011, 10:26:00 AM8/5/11
to android-ndk

> Very interesting.  Just to clarify, when you say communicate, do you mean
> using pipes/other IPC or is there some other Android-esque way of doing this
> that I don't know about?

I meant the standard C/Java network stuff. Pick a socket and go. Or
you
can hope that the NativeDaemonConnector doesn't get broken by the OEM
or
have it's behavior changed/moved by the google developers.

David Turner

unread,
Aug 5, 2011, 10:35:26 AM8/5/11
to andro...@googlegroups.com
For the record, calling "am start" directly is not a supported system feature. There is no guarantee that it will work in the future (e.g. unless you're the system process or something equally privileged).

        Dan


--
You received this message because you are subscribed to the Google Groups "android-ndk" group.
Reply all
Reply to author
Forward
0 new messages