androidandroid-ndkarmrootcodesourcery

Is it possible to run a native arm binary on a non-rooted android phone?


Well, I've been diving in the murky waters of low-level Android programming (native C/C++ using the CodeSourcery toolchain). I tried out the executable on an emulator and it worked. I'd like to try it out on a real device. So I plugged in my nexus and pushed the files on to the filesystem. Then I tried to execute the binary, and I got a permission error. It really doesn't matter how I mount it, or where I send it, I'm not root and it's not letting me execute it. Is there any way to run a program like this on a non-rooted phone?


Solution

  • Update: notice that apps targeting API level 29 (Android 10) and above will not be able to use the trick below, as the OS will restrict the execute permission. See Behavior changes: apps targeting API 29+.

    After using the toolchain included in the Android NDK to compile your binaries, it is possible to package them with a typical Android app and have them spawn as subprocesses.

    You'll have to include all the necessary files within the assets folder of your application. In order to run them, you have to have the program copy them from the assets folder to a runnable location like: /data/data/com.yourdomain.yourapp/nativeFolder

    You can do this like so:

    private static void copyFile(String assetPath, String localPath, Context context) {
        try {
            InputStream in = context.getAssets().open(assetPath);
            FileOutputStream out = new FileOutputStream(localPath);
            int read;
            byte[] buffer = new byte[4096];
            while ((read = in.read(buffer)) > 0) {
                out.write(buffer, 0, read);
            }
            out.close();
            in.close();
        
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
    

    Keep in mind that the assetPath is not absolute but in respect to assets/.

    IE: "assets/nativeFolder" is just "nativeFolder"

    To then run your application and read its output you could do something like this:

      Process nativeApp = Runtime.getRuntime().exec("/data/data/com.yourdomain.yourapp/nativeFolder/application");
                                
                            
                BufferedReader reader = new BufferedReader(new InputStreamReader(nativeApp.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();
                
                // Waits for the command to finish.
                nativeApp.waitFor();
                
                String nativeOutput =  output.toString();