Подтвердить что ты не робот

Хостинг исполняемого файла в приложении Android

Я работаю над приложением Android, которое зависит от двоичного файла ELF: наш Java-код взаимодействует с этим двоичным кодом, чтобы все было сделано. Эта время запуска должно быть запущено и завершено при запуске приложения и выход приложения/по требованию.

Вопросы:

  • Я предполагаю, что мы сможем выполнить этот двоичный код, используя Runtime.exec(). Существуют ли какие-либо ограничения относительно того, где я нужно поместить мою библиотеку в структуру папок? Как бы среда выполнения системы находила этот исполняемый файл? Есть ли какие-то настройки класса?

  • Поскольку приложение имеет зависимости от этого времени выполнения, я был думая об обертке вокруг службы, чтобы ее можно было запустить или по необходимости. Каков наилучший способ обработки таких исполняемых файлов в проекте Android?

  • Каковы другие альтернативы, предполагая, что у меня нет исходного кода для этого исполняемого файла?

Пожалуйста, совет.

Спасибо.

4b9b3361

Ответ 1

1) Нет, не должно быть ограничений, кроме тех, которые получают доступ к системным файлам и, следовательно, требуют root. Лучшее место было бы прямо в /data/data/ [your_package_name], чтобы избежать загрязнения в другом месте.

2) Очень подробное обсуждение компиляции в отношении родных библиотек можно найти здесь: http://www.aton.com/android-native-libraries-for-java-applications/. Другой вариант - кросс-компилятор для руки (вот тот, который использовался для компиляции ядра, он бесплатный: http://www.codesourcery.com/sgpp/lite/arm). Если вы планируете поддерживать службу, которая выполняет ваш cammand, будьте предупреждены о том, что службы могут быть остановлены и перезагружены андроидом в любой момент.

3) Теперь, если у вас нет исходного кода, я надеюсь, что ваш файл, по крайней мере, скомпилирован как исполняемый файл руки. Если нет, я не понимаю, как вы могли его запустить.


Вы выполните файл, выполнив следующие команды в своем классе 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());

Я ничего не знаю о вашем исполняемом файле, так что вам может понадобиться или не понадобиться фактически получать inputStream и outputStream.


Я предполагаю, что запуск adb для push двоичного файла не может быть и речи, поэтому Я искал опрятный способ его упаковки. Я нашел отличный пост о включении исполняемого файла в ваше приложение. Проверьте это здесь: http://gimite.net/en/index.php?Run%20native%20executable%20in%20Android%20App

Важная часть - это одна (внимание мое):

Из приложения Android Java, используя папку assets

  • Включите двоичный файл в папке с ресурсами.
  • Используйте getAssets().open(FILENAME) для получения InputStream.
  • Запишите его на /data/data/APPNAME (например, /data/data/net.gimite.nativeexe), где ваше приложение имеет доступ к файлам записи и делает его исполняемым.
  • Запустите /system/bin/chmod 744 /data/data/APPNAME/FILENAME с помощью приведенного выше кода.
  • Запустите исполняемый файл, используя приведенный выше код.

Сообщение использует папку assets, установленную в папку raw, которую предлагает андроид для статических файлов:

Совет. Если вы хотите сохранить статический файл в своем приложении во время компиляции, сохраните файл в каталоге проекта res/raw/. Вы можете открыть его с помощью openRawResource(), передав R.raw. идентификатор ресурса. Этот метод возвращает InputStream, который вы можете использовать для чтения файла (но вы не можете записать его в исходный файл).

Чтобы получить доступ к папке с данными, вы можете выполнить следующие инструкции: http://developer.android.com/guide/topics/data/data-storage.html#filesInternal Кроме того, существует File#setExecutable(boolean); метод, который должен работать вместо команды оболочки.

Итак, поставив все вместе, я бы попытался:

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);

Конечно, все это нужно делать только один раз после установки. Вы можете быстро проверить внутри onCreate() или все, что проверяет наличие файла и выполняет все эти команды, если файл там отсутствует.

Сообщите мне, если это сработает. Удачи!

Ответ 2

Вот полное руководство по пакету и запуску исполняемого файла. Я основывал его на том, что я нашел здесь, и на других ссылках, а также на моих собственных проб и ошибок.

1.) В проекте SDK поместите исполняемый файл в папку /assets

2.) Программно получить строку этого каталога файлов (/data/data/your_app_name/files), подобную этой

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

3.) В вашем проекте Java-код проекта: скопируйте исполняемый файл из папки /assets в подпапку "файлы" вашего приложения (обычно/data/data/your_app_name/files) с помощью следующей функции:

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.) Измените права на файл для исполняемого файла, чтобы фактически сделать его исполняемым. Сделайте это с помощью Java-вызовов:

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

5.) Выполните файл следующим образом:

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

Обратите внимание, что любые файлы, упомянутые здесь (такие как входные и выходные файлы), должны иметь полный путь Строки, построенные. Это потому, что это отдельный порожденный процесс, и он не имеет понятия о том, что такое "pwd".

Если вы хотите прочитать команду stdout, вы можете это сделать, но пока она работает только для меня для системных команд (например, "ls" ), а не для исполняемого файла:

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, "output:" + output.toString());

Ответ 3

Я сделал что-то подобное, используя NDK. Моя стратегия заключалась в том, чтобы перекомпилировать программу с использованием NDK и написать некоторый код JNI-оболочки, который вызывается в функцию main.

Я не уверен, что такое жизненный цикл кода NDK. Даже услуги, которые предназначены для долговременного использования, могут быть запущены и остановлены системой, когда это удобно. Вам, вероятно, придется отключить поток NDK и при необходимости перезапустить его.