3

I'm building a application which makes use of a Native service binary file.

Now my requirements are:

Place the native service binary file in the assets folder of application.

  1. When the application runs, copy this native file in the device (path like getExternalFilesDir(null))
  2. Execute this binary file within the device.
  3. Check if the file has been succesfully executed in logs.

Now to copy the file, I've used:

private void copyAssets() {
    AssetManager assetManager = getAssets();
    String[] files = null;
    try {
        files = assetManager.list("");
    } catch (IOException e) {
        Log.e("tag", "Failed to get asset file list.", e);
    }
    for (String filename : files) {
        if (filename.equals("native-file")) { // native-file is the file name present is assets folder
            InputStream in = null;
            OutputStream out = null;
            try {
                in = assetManager.open(filename);
                File outFile = new File(getExternalFilesDir(null), filename);
                out = new FileOutputStream(outFile);
                copyFile(in, out);
                in.close();
                in = null;
                out.flush();
                out.close();
                out = null;

            } catch (IOException e) {
                Log.e("tag", "Failed to copy asset file: " + filename, e);
            }
            break;
        }
    }
}

And after copying to execute the file I'm using:

File sdCard = getExternalFilesDir(null); // directory where native file is placed
Process proc = Runtime.getRuntime().exec("sh -c shell " + sdCard.getAbsolutePath() + "/native-file "+ sdCard.getAbsolutePath() +"/native-file.log\" "); // command 1
proc = Runtime.getRuntime().exec("sh -c less " + sdCard.getAbsolutePath() +"/native-file.log\""); // command 2

Issues:

  1. How can I make sure that the file is placed.
  2. How to make sure the that it is executed. Because I'm not able to find and log files (native-file.log) when I run the application.

PS - I can not provide my JNI file due to proprietry issues. So i guess we can use an opensource asl library.(there is a native file by name asl-native)

adam black
  • 607
  • 5
  • 14

1 Answers1

2

Your current code is not too far off, but there's a few details you need to take care of:

  1. As already have been commented, you can't execute files that you've put in /sdcard. You can however execute files in the internal memory. Thus, instead of getExternalFilesDir(null), use getFilesDir()
  2. After copying the executable to the target directory, you need to make it executable. You can either run Runtime.getRuntime().exec("chmod 755 " + getFilesDir() + "/native-file").waitFor(); or try using the private android.os.FileUtils class (as in https://stackoverflow.com/a/11408378/3115956).
  3. You don't need any extra "sh -c shell" when starting your app, this is enough: Process proc = Runtime.getRuntime().exec(getFilesDir() + "/native-file");
  4. If you want to read stdout/stderr output from your executable (to verify that it run correctly), you can do e.g. this:

    InputStream stdout = proc.getInputStream();
    InputStream stderr = proc.getErrorStream();
    BufferedReader br = new BufferedReader(new InputStreamReader(stdout));
    String line;
    while ((line = br.readLine()) != null)
        System.out.println("stdout: " + line);
    br = new BufferedReader(new InputStreamReader(stderr));
    while ((line = br.readLine()) != null)
        System.out.println("stderr: " + line);
    

To simplify steps 1 and 2, and to avoid having to take care of the different architectures for native binaries yourself, you could rename your command line executable to match the pattern lib<something>.so and put it in the libs/<abi> directory in your project. Then it will be picked up by the APK packager and be packaged like any native library. To execute it, you can simply do Process proc = Runtime.getRuntime().exec(getApplicationInfo().nativeLibraryDir + "/libnative-file.so");

Community
  • 1
  • 1
mstorsjo
  • 12,983
  • 2
  • 39
  • 62
  • Sorry for delay & thank you. The permission change works I guess because the waitfor() command is returning 0. But `exec(getFilesDir() + "/native-file");` is returning `1 & no stdout is printed but stderr is printing `stderr: Error while starting server (errno=13): Permission denied`. I tried using asl native file mentioned in my question. Any suggestions? And also how to rename my command to .so, can you please explain. – adam black Nov 29 '14 at 08:58
  • First you can check whether your native binary actually can run on your device at all - you can try to send it to the device and run it using `adb push native-file /data/local/tmp` and `adb shell /data/local/tmp/native-file` - if this doesn't work, something is wrong with your file (outside of the scope of this question). To rename it to .so, do `mkdir -p libs/armeabi` and `cp assets/native-file libs/armeabi/libnative-file.so`. You need to replace `armeabi` with the right ABI name the binary is built for, that the device uses. – mstorsjo Nov 29 '14 at 14:34