OS.Execute() not working on Android

Godot Version

4.2

Question

My mobile game should be able to run an executable on an Android phone.

Making the executable: I installed Android NDK, created a JNI Folder and Android.mk file, and compiled an executable named servTest in C. Then, took the file from the libs ->arm64-v8a folder.

Code in C:

#include <stdio.h>

int returnFive() {
    return 5;
}

int main() {
    int result = returnFive();
    printf("The result is: %d\n", result);

    return 0;
}

Running the executable:
First, I parse the compiled file to the device if it wasn’t already in the past.

var desiredPermissions = FileAccess.UnixPermissionFlags.ReadOwner |
                                         FileAccess.UnixPermissionFlags.WriteOwner |
                                         FileAccess.UnixPermissionFlags.ExecuteOwner |
                                         FileAccess.UnixPermissionFlags.ReadGroup |
                                         FileAccess.UnixPermissionFlags.ReadOther;

if (OS.GetName() == "Android")
{
      if (FileAccess.FileExists(iopiperMobileUserPath))
      {
        using var servFile = FileAccess.Open(iopiperMobileUserPath, FileAccess.ModeFlags.ReadWrite);
        iopiper = servFile.GetPathAbsolute();
      }
      else
      {
        iopiper = CopyFromRes(iopiperMobileProjPath, iopiperMobileUserPath, desiredPermissions);
      }
}

public static string CopyFromRes(string from, string to, FileAccess.UnixPermissionFlags UPFlags = 0)
{
      using var fileFrom = FileAccess.Open(from, FileAccess.ModeFlags.Read);
      GD.Print("CopyFromRes Open(from) status: ", FileAccess.GetOpenError());
      using var fileTo = FileAccess.Open(to, FileAccess.ModeFlags.Write);
      fileTo.StoreBuffer(fileFrom.GetBuffer((long)fileFrom.GetLength()));
      string path = fileTo.GetPathAbsolute();
      if (UPFlags != 0)
    {
      var error = FileAccess.SetUnixPermissions(to, UPFlags);
      if (error != Error.Ok)
      {
          GD.Print("Error setting permissions: " + error);
      }
}
return path;}

The file is copied successfully and then I try to run it using this method:

public void TestServer()
{
    var output = new Godot.Collections.Array();
    int exit = OS.Execute(iopiper, new string[] { engine }, output, true);
    GD.Print("exit: " + exit);
    GD.Print("output: " + output);
}

Here is the result I get:


(I turned on the internet permission)

Did you set the execute permissions here?

And who is the owner of this file? Does it defaults to root/system or does the game process own the binary?

My “desiredPermissions” variable is the setup of UnixPermissionFlags for the file.
The file is written to the data/data folder of the game and the game process is supposed to own the binary. Is there a way to ensure/check it does?

I mean you could go onto the phone and look at the file if you start an adb shell ls -al <path to file>. or if there isnt a fileaccess function to get permission and group/owner you could use the ls command in an execute to get the status of the file and do some string search. But starting an adb shell would be easier.

Do you do adb root first? I guess I’m used to unlocked devices, so I don’t know if that is possible to use that command on a normal phone.

You could have the game execute that ls command and you could just print the output for visual inspection. My guess is that the data path is owned by the game, and that is why it can’t be accessed by an underprivileged shell. But if the game ls’d its own path it should work.

I guess you could use Android studio to inspect the filesystem as well.

Oh shoot nvm

Hmm…

IDK this seems like an android problem…

1 Like

https://issuetracker.google.com/issues/128554619?pli=1

Not sure I can help any further, here is someone talking about how binary execution has changed since version 28.

I would suggest looking around at android related questions on this matter.

Just to be clear the Godot execution command will be internally using exec() OS function.


maybe it’s just not allowed