How to build an executable for Android shell
Asked Answered
N

3

13

Sometimes I need to run a command or script on my device, but they are not available or don't exist.

Can we add some additional commands to Android device's shell, except those commands that are already available on it?

For example, add screenrecord command to my device (my device has Android API lower than 19), which this is unavailable on it.

I know how to get the list of available commands on the device with adb shell

adb shell ls /system/bin 

but I want to add more custom commands and scripts, to do some special and work.

Is there any way to do it? Or it's impossible?

Nonna answered 5/2, 2016 at 18:35 Comment(1)
See the official guide(s), the answers here are outdated or unnecessarily complex. For the easiest method (one line compile, no build system), see this.Parsec
T
50

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.

  1. Add native support. Right click on the project in Project Explorer > Android Tools > Add Native Support > Finish

  2. Add source code, i.e. put mycommand.c under project_root/jni folder.

  3. Edit Android.mk under project_root/jni as follows:

    LOCAL_PATH := $(call my-dir)
    
    include $(CLEAR_VARS)
    
    LOCAL_MODULE     := mycommand
    LOCAL_SRC_FILES  := mycommand.c
    
    include $(BUILD_EXECUTABLE)
    
  4. Create Application.mk * under the project_root/jni folder:

    APP_ABI := all
    
  5. 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.

  1. Add mycommand.c, Android.mk (same as in the Eclipse section above) to the /app/src/main/cpp folder.

  2. 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"
            }
        }
    }
    
  3. Build project and find the executable under /app/.externalNativeBuild/ndkBuild/debug/obj/local/<abi>/mycommand


Android Studio and CMake

  1. Create a project using the Native C++ template.

  2. Add mycommand.c to the /app/src/main/cpp folder and edit CMakeLists.txt:

    cmake_minimum_required(VERSION x.x.x)
    
    add_executable(mycommand
                   mycommand.c )
    
  3. 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"
            }
        }
    }
    
  4. 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!
    
Thrum answered 8/2, 2016 at 17:2 Comment(7)
On the step 3, you could run adb root && adb remount, which should simplify things, especially for the recent Android releasesSavill
Ok. I created and empty project., added mycommand.c and Android.mk to the cpp folder I created in app/src/main/ and edited build.gradle by simply adding what recommanded (for the ndk case in it) and then make build apk. The build failed with the following error :Scientism
"Could not find method android() for arguments [build_4wbyjnnxfo36n8uu8rkjatpia$_run_closure1@332ef9dd] on root project 'MyConsoleApplication4' of type org.gradle.api.Project."Scientism
Hi, sorry for the delay. Currently in Android Studio you should choose Native C++ template located on the Phone and Tablet tab (scroll down to the template).Thrum
Currently the Android-Studio-with-CMake part of the answer is up-to-date.Thrum
Any example without android studio? I need flag for build because i got error TLS segment is underalignedBluma
Is it possible to package the built exeutable binaries automatically inside an app's module? Like in assets folder or so?Salena
A
3

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.

Accessary answered 7/4, 2019 at 21:46 Comment(0)
R
2

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
  }
 }
...........
}
Raul answered 1/3, 2018 at 21:53 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.