rahmat waisi rahmat waisi - 6 months ago 19
Bash Question

How to add more executables to Android Shell?

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?

Answer

The answer provides a sequence of steps for adding an extra executable file to Android device. As building tool Android NDK is used within both Eclipse and Android Studio IDEs.


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

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. Project > Build Project.

*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

The example of building executable shown below is based on HelloJNI sample. I recommend to use it in order to preserve consistency of the Gradle build system (Gradle 2.8) / plugin version (gradle-experimental:0.4.0).

AFAIK, by the time of this writing android.ndk module of build.gradle doesn't have the option to build executables yet. In this case the steps are as follows.

  1. Use regular *.mk files by setting the location of source files to non-existing folder and jniLibs location to libs folder in build.gradle:

    android.sources{
        main {
            jni {
                source { srcDir "src/main/none" }
            }
            jniLibs {
                source { srcDir "src/main/libs" }
            }
        }
    }
    
  2. Add mycommand.c, Android.mk, Application.mk (same as in Eclipse section above) under the project_app_root/src/main/jni folder.

  3. Build executable either

    • manually in command line by executing from project_app_root/src/main directory the path_to_ndk/ndk-build script;
    • or calling the ndk-build script in build.gradle ** (Build > Make Project):

      import org.apache.tools.ant.taskdefs.condition.Os
      
      model {
          ...
      }
      
      task ndkBuild(type: Exec) {
          if (Os.isFamily(Os.FAMILY_WINDOWS)) {
              commandLine 'ndk-build.cmd', '-C', file('src/main').absolutePath
          } else {
              commandLine 'ndk-build', '-C', file('src/main').absolutePath
          }
      }
      
      tasks.withType(JavaCompile) {
          compileTask -> compileTask.dependsOn ndkBuild
      }
      

**If you run into Error:Execution failed for task ':app:ndkBuild'. A problem occurred starting process 'command 'ndk-build(.cmd)'', try setting the full path to ndk-build(.cmd) command.


III. PUSH BINARY INTO DEVICE

Push mycommand binary from project_root/libs/<abi> (Eclipse) or project_app_root/src/main/libs/<abi> (Android Studio) into your device. Keep in mind that files on SD card aren't executable, 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
    su
    mount -o rw,remount /system
    cp /path/to/sdcard/mycommand /system/bin
    

IV. SET EXECUTABLE PERMISSION

Set the permission of the binary to be executable. Below chmod 555(r-xr-xr-x) is used:

adb shell chmod 555 /data/local/tmp/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/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!