Alojando un ejecutable dentro de la aplicación de Android

Estoy trabajando en una aplicación de Android que depende de un binario ELF: nuestro código Java interactúa con este binario para hacer las cosas. Este tiempo de ejecución debe iniciarse y finalizar en el inicio de la aplicación y la salida de la aplicación / a pedido.

Preguntas:

  1. Supongo que podremos ejecutar este binario utilizando la API Runtime.exec (). ¿Hay alguna restricción en cuanto a dónde debo colocar mi biblioteca en la estructura de carpetas? ¿Cómo ubicaría el tiempo de ejecución del sistema este ejecutable? ¿Hay algún tipo de configuración de ruta de clase?

  2. Dado que la aplicación tiene dependencias en este Runtime, estaba pensando envolverlo en un servicio para que pueda iniciarse o detenerse según sea necesario. ¿Cuál es la mejor manera de manejar dichos ejecutables en un proyecto de Android?

  3. ¿Cuáles son otras alternativas, suponiendo que no tengo el código fuente para este ejecutable?

Por favor aconséjame.

Gracias.

1) No, no debe haber restricciones, además de las que acceden a los archivos del sistema y, por lo tanto, requieren root. El mejor lugar sería directamente a / data / data / [your_package_name] para evitar contaminar en otro lugar.

2) Puede encontrar una discusión muy completa sobre la comstackción contra bibliotecas nativas aquí: http://www.aton.com/android-native-libraries-for-java-applications/ . Otra opción es un comstackdor cruzado para armar (este es el que se usa para comstackr el núcleo, es gratis: http://www.codesourcery.com/sgpp/lite/arm ). Si planea mantener un servicio que ejecute su cammand, tenga en cuenta que los servicios pueden ser detenidos y reiniciados por Android en cualquier momento.

3) Ahora, si no tiene el código fuente, espero que su archivo esté como mínimo comstackdo como un ejecutable de arm. Si no, no veo cómo podrías incluso ejecutarlo.


Ejecutará el archivo ejecutando los siguientes comandos en su clase java:

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

No sé nada sobre su ejecutable, por lo que puede o no necesitar obtener realmente inputStream y outputStream.


Estoy asumiendo que ejecutar adb para enviar el archivo binario está fuera de discusión, así que estaba buscando una forma ordenada de empaquetarlo. Encontré una excelente publicación sobre cómo incluir un ejecutable en tu aplicación. Compruébelo aquí: http://gimite.net/en/index.php?Run%20native%20executable%20in%20Android%20App

La parte importante es esta (el énfasis es mío):

Desde la aplicación Android de Java, usando la carpeta de assets

  • Incluye el binario en la carpeta de activos.
  • Use getAssets().open(FILENAME) para obtener un InputStream .
  • Escríbalo a /data/data/APPNAME (por ejemplo, /data/data/net.gimite.nativeexe ), donde tu aplicación tenga acceso para escribir archivos y hacer que sea ejecutable.
  • Ejecute /system/bin/chmod 744 /data/data/APPNAME/FILENAME utilizando el código anterior.
  • Ejecuta tu ejecutable usando el código de arriba.

La publicación utiliza la carpeta assets , insted de la carpeta raw que Android sugiere para los archivos estáticos:

Consejo: si desea guardar un archivo estático en su aplicación en tiempo de comstackción, guarde el archivo en el directorio res / raw / del proyecto. Puede abrirlo con openRawResource (), pasando el R.raw. ID de recurso. Este método devuelve un InputStream que puede usar para leer el archivo (pero no puede escribir en el archivo original).

Para acceder a la carpeta de datos, puede seguir las instrucciones aquí: http://developer.android.com/guide/topics/data/data-storage.html#filesInternal Además, está el File#setExecutable(boolean); método que debería funcionar en lugar del comando de shell.

Entonces, juntando todo, lo intentaría:

 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 = getFileStreamPath (FILENAME); file.setExecutable(true); 

Por supuesto, todo esto debe hacerse solo una vez después de la instalación. Puede hacer una comprobación rápida dentro onCreate() o lo que sea que compruebe la presencia del archivo y ejecuta todos estos comandos si el archivo no está allí.

Déjame saber si funciona. ¡Buena suerte!

Aquí hay una guía completa sobre cómo empaquetar y ejecutar el ejecutable. Lo basé en lo que encontré aquí y en otros enlaces, así como en mi propio ensayo y error.

1.) En su proyecto de SDK, coloque el archivo ejecutable en su carpeta / assets

2.) Obtenga programáticamente el directorio String of that files (/ data / data / your_app_name / files) como este

 String appFileDirectory = getFilesDir().getPath(); String executableFilePath = appFileDirectory + "/executable_file"; 

3.) En el código Java del proyecto de su aplicación: copie el archivo ejecutable de la carpeta / assets en la subcarpeta “archivos” de su aplicación (normalmente / data / data / your_app_name / files) con una función como esta:

 private void copyAssets(String filename) { AssetManager assetManager = getAssets(); InputStream in = null; OutputStream out = null; Log.d(TAG, "Attempting to copy this file: " + filename); // + " to: " + assetCopyDestination); try { in = assetManager.open(filename); Log.d(TAG, "outDir: " + appFileDirectory); File outFile = new File(appFileDirectory, 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); } Log.d(TAG, "Copy success: " + filename); } 

4.) Cambie los permisos de archivo en archivo_de_ejecución para hacerlo realmente ejecutable. Hazlo con llamadas Java:

 File execFile = new File(executableFilePath); execFile.setExecutable(true); 

5.) Ejecuta el archivo así:

 Process process = Runtime.getRuntime().exec(executableFilePath); 

Tenga en cuenta que los archivos a los que se hace referencia aquí (como archivos de entrada y salida) deben tener su ruta completa Cadenas construidas. Esto se debe a que este es un proceso separado generado y no tiene ningún concepto de lo que es el “pwd”.

Si desea leer el comando stdout puede hacerlo, pero hasta ahora solo funciona para mí los comandos del sistema (como “ls”), no el archivo ejecutable:

 BufferedReader reader = new BufferedReader( new InputStreamReader(process.getInputStream())); int read; char[] buffer = new char[4096]; StringBuffer output = new StringBuffer(); while ((read = reader.read(buffer)) > 0) { output.append(buffer, 0, read); } reader.close(); process.waitFor(); 

Log.d (TAG, “salida:” + salida.a.cadena ());

He hecho algo como esto usando el NDK. Mi estrategia era recomstackr el progtwig usando el NDK y escribir algún código envoltorio JNI que llamara a la función main del progtwig.

No estoy seguro de cómo es el ciclo de vida del código NDK. Incluso los servicios que están destinados a ser de larga duración pueden ser iniciados y detenidos por el sistema cuando sea conveniente. Probablemente tendrías que apagar tu hilo NDK y reiniciarlo cuando sea necesario.