How to build an executable for Android shell
The answer provides a sequence of steps for building an executable for Android shell
through both Eclipse
(outdated) and Android Studio
(4.1+ by the time of this writing). The last includes ndk-build
and CMake
.
I. PREPARE SOURCE CODE
As an example consider mycommand.c
:
#include <stdio.h>
int main()
{
printf("My Command!\n");
return 0;
}
II. BUILD EXECUTABLE
Eclipse (might be outdated)
In assumption that NDK
location is set in Eclipse
, create a new Android Application Project
and do the following steps.
-
Add native support. Right click on the project in
Project Explorer
>Android Tools
>Add Native Support
>Finish
-
Add source code, i.e. put
mycommand.c
underproject_root
/jni
folder. -
Edit
Android.mk
underproject_root
/jni
as follows:LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := mycommand LOCAL_SRC_FILES := mycommand.c include $(BUILD_EXECUTABLE)
-
Create
Application.mk
* under theproject_root
/jni
folder:APP_ABI := all
-
Build executable and find it under
project_root/libs/<abi>/mycommand
.
*Binaries for all
supported CPU architectures are generated here. Use adb shell cat /proc/cpuinfo
to find out the CPU architecture and set APP_ABI
as per Supported ABIs.
Android Studio and ndk-build
The steps are as follows.
-
Add
mycommand.c
,Android.mk
(same as in theEclipse
section above) to the/app/src/main/cpp
folder. -
Edit
build.gradle
:android { ... defaultConfig { ... externalNativeBuild { ndkBuild { targets "mycommand" // use a specific ABI filter if needed // abiFilters "armeabi-v7a" } } } externalNativeBuild { ndkBuild { path "src/main/cpp/Android.mk" } } }
-
Build project and find the executable under
/app/.externalNativeBuild/ndkBuild/debug/obj/local/<abi>/mycommand
Android Studio and CMake
-
Create a project using the Native C++ template.
-
Add
mycommand.c
to the/app/src/main/cpp
folder and editCMakeLists.txt
:cmake_minimum_required(VERSION x.x.x) add_executable(mycommand mycommand.c )
-
Edit
build.gradle
:android { ... defaultConfig { ... externalNativeBuild { cmake { targets "mycommand" // use a specific ABI filter if needed // abiFilters "armeabi-v7a" } } } ... externalNativeBuild { cmake { path "src/main/cpp/CMakeLists.txt" } } }
-
Build project and find the executable under
/app/build/intermediates/cmake/debug/obj/<abi>/mycommand
III. PUSH BINARY INTO DEVICE
Push mycommand
binary from where it is located into your device. Keep in mind that files on SD card aren't executable by default, so the binary should be pushed into the device's internal storage. Depending of whether device is rooted or not you have the following options:
-
On non-rooted device you can push the binary to
/data/local/tmp
:adb push mycommand /data/local/tmp
-
On rooted device you can push the binary to SD card and then copy it to
/system/bin
(after remounting the partition in read-write mode) along with the other executable files:adb push mycommand /path/to/sdcard adb shell su mount -o rw,remount /system cp /path/to/sdcard/mycommand /system/bin
IV. SET EXECUTABLE PERMISSION (optional)
Set the permission of the binary to be executable (this might not be needed in case of /data/local/tmp
). Below chmod 555
(r-xr-xr-x) is used:
adb shell chmod 555 /path/to/mycommand
V. RUN COMMAND
Now you can shell into your device (with adb shell
) and execute the command.
-
On non-rooted device use the absolute path to the command:
$ /data/local/tmp/mycommand My Command!
-
On rooted device, in case the binary has been copied to
/system/bin
, you can call it by the file name:$ mycommand My Command!
In case you dont have binaries at this location for Android and ndk-build, they are at
app\build\intermediates\ndkBuild\debug\obj\local\arm64-v8a\objs-debug\test1
for arm64-v8a and corresponding for other platforms.
If in case you are getting this error:
error: only position independent executables (PIE) are supported when you created the executable using CMake,
add these lines to app gradle
default config
{
..........
..........
externalNativeBuild
{
cmake
{
targets "my_command"
abiFilters "armeabi-v7a"
arguments "-DANDROID_PIE=ON" //important
}
}
...........
}