Copy and execute custom binary and audit service logs
I am creating an application that uses a Native service binary.
Now my requirements are:
Place your own service binary in your application's assets folder.
- When the app starts, copy this native file to the device (path as
getExternalFilesDir(null)
) - Execute this binary inside the device.
- Check if the file was executed successfully in the logs.
Now, to copy the file, I 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 am 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
Questions:
- How can I make sure the file is placed.
- How to make sure it's done. As I cannot find and write the files (native-file.log) when starting the application.
PS - I am unable to provide the JNI file due to permissions issues. So I guess we can use the opensource asl library (there is a native file called asl-native)
source to share
Your current code isn't too far off, but there are a few details you need to take care of:
- As noted, you cannot execute files that you entered into
/sdcard
. However, you can execute files in the internal memory. So insteadgetExternalFilesDir(null)
usegetFilesDir()
- After copying the executable to the target directory, it needs to be executed. You can run
Runtime.getRuntime().exec("chmod 755 " + getFilesDir() + "/native-file").waitFor();
or try using a privateandroid.os.FileUtils
class (as in fooobar.com/questions/1422362 / ... ). - When starting the application, you do not need an additional "sh -c shell", this is enough:
Process proc = Runtime.getRuntime().exec(getFilesDir() + "/native-file");
-
If you want to read the stdout / stderr output from your executable (to make sure it works correctly), you can do so for example. this is:
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 worry about different architectures for your own binaries yourself, you can rename your command line executable according to the pattern lib<something>.so
and place it in a directory libs/<abi>
in your project. It will then be picked up by the APK packer and packaged like any native library. To accomplish it, you can simply doProcess proc = Runtime.getRuntime().exec(getApplicationInfo().nativeLibraryDir + "/libnative-file.so");
source to share