Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
126 views
in Technique[技术] by (71.8m points)

java - Hosting an executable within Android application

I am working on an Android application that depends on an ELF binary: our Java code interacts with this binary to get things done. This runtime needs to be started and terminated on Application startup and application exit / on demand.

Questions:

  1. I am assuming that we will be able to execute this binary using the Runtime.exec() API. Is there any constraints as to where I need to be putting my library in the folder structure? How would the system runtime locate this executable? Is there some sort of class path setting?

  2. Since the application has dependencies on this Runtime, I was thinking of wrapping it around a service so that it can be started or stopped as required. What is the best way to handle such executables in Android project?

  3. What are other alternatives, assuming that I do not have source code for this executable?

Please advice.

Thanks.

Question&Answers:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

1) No, there should be no constrains, besides those that access system files and thus require root. The best place would be straight to /data/data/[your_package_name] to avoid polluting elsewhere.

2) A very thorough discussion about compiling against native libraries can be found here: http://www.aton.com/android-native-libraries-for-java-applications/ . Another option is a cross-compiler for arm (here is the one used to compile the kernel, it's free: http://www.codesourcery.com/sgpp/lite/arm ). If you plan to maintain a service that executes your cammand, be warned that services can be stopped and restarted by android at any moment.

3) Now, if you don't have the source code, I hope that your file is at least compiled as an arm executable. If not, I don't see how you could even run it.


You will execute the file by running the following commands in your java class:

String myExec = "/data/data/APPNAME/FILENAME";
Process process = Runtime.getRuntime().exec(myExec);
DataOutputStream os = new DataOutputStream(process.getOutputStream());
DataInputStream osRes = new DataInputStream(process.getInputStream());

I know nothing about your executable, so you may or may not need to actually get the inputStream and outputStream.


I am assuming that running adb to push the binary file is out of the question, so I was looking for a neat way to package it. I found a great post about including an executable in your app. Check it out here: http://gimite.net/en/index.php?Run%20native%20executable%20in%20Android%20App

The important part is this one (emphasis mine):

From Android Java app, using assets folder

  • Include the binary in the assets folder.
  • Use getAssets().open(FILENAME) to get an InputStream.
  • Write it to /data/data/APPNAME (e.g. /data/data/net.gimite.nativeexe), where your application has access to write files and make it executable.
  • Run /system/bin/chmod 744 /data/data/APPNAME/FILENAME using the code above.
  • Run your executable using the code above.

The post uses the assets folder, insted of the raw folder that android suggests for static files:

Tip: If you want to save a static file in your application at compile time, save the file in your project res/raw/ directory. You can open it with openRawResource(), passing the R.raw. resource ID. This method returns an InputStream that you can use to read the file (but you cannot write to the original file).

To access the data folder, you can follow the instructions here: http://developer.android.com/guide/topics/data/data-storage.html#filesInternal Also, there's the File#setExecutable(boolean); method that should works instead of the shell command.

So, putting everything together, I would try:

InputStream ins = context.getResources().openRawResource (R.raw.FILENAME)
byte[] buffer = new byte[ins.available()];
ins.read(buffer);
ins.close();
FileOutputStream fos = context.openFileOutput(FILENAME, Context.MODE_PRIVATE);
fos.write(buffer);
fos.close();


File file = context.getFileStreamPath (FILENAME);
file.setExecutable(true);

Of course, all this should be done only once after installation. You can have a quick check inside onCreate() or whatever that checks for the presence of the file and executes all this commands if the file is not there.

Let me know if it works. Good luck!


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...