Skip to content

Commit

Permalink
Merge pull request ddnet#9474 from Robyt3/Android-Server-Launch-Argum…
Browse files Browse the repository at this point in the history
…ents

Support passing launch arguments to Android server
  • Loading branch information
def- authored Jan 3, 2025
2 parents 3988f32 + 640bf6f commit 24d9705
Show file tree
Hide file tree
Showing 6 changed files with 85 additions and 29 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -96,12 +96,12 @@ private void restartApp() {
}

// Called from native code, see android_main.cpp
public void startServer() {
public void startServer(String[] arguments) {
synchronized(serverServiceMonitor) {
if(serverServiceMessenger != null) {
return;
}
Intent startIntent = new Intent(this, ServerService.class);
Intent startIntent = ServerService.createStartIntent(this, arguments);
ContextCompat.startForegroundService(this, startIntent);
bindService(startIntent, serverServiceConnection, 0);
}
Expand All @@ -114,9 +114,7 @@ public void executeCommand(String command) {
return;
}
try {
Message message = Message.obtain(null, ServerService.MESSAGE_CODE_EXECUTE_COMMAND, 0, 0);
message.getData().putString(ServerService.MESSAGE_EXTRA_COMMAND, command);
serverServiceMessenger.send(message);
serverServiceMessenger.send(ServerService.createExecuteCommandMessage(command));
} catch (RemoteException e) {
// Connection broken
unbindService(serverServiceConnection);
Expand Down
57 changes: 41 additions & 16 deletions scripts/android/files/java/org/ddnet/client/ServerService.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,12 @@ public class ServerService extends Service {
private static final String NOTIFICATION_CHANNEL_ID = "LOCAL_SERVER_CHANNEL_ID";
private static final int NOTIFICATION_ID = 1;

public static final int MESSAGE_CODE_EXECUTE_COMMAND = 1;
public static final String MESSAGE_EXTRA_COMMAND = "command";
private static final int MESSAGE_CODE_EXECUTE_COMMAND = 1;
private static final String MESSAGE_EXTRA_COMMAND = "command";

public static final String INTENT_ACTION_EXECUTE = "execute";
public static final String INTENT_EXTRA_COMMAND = "command";
private static final String INTENT_ACTION_START = "start";
private static final String INTENT_ACTION_EXECUTE = "execute";
private static final String INTENT_EXTRA_COMMANDS = "commands";
private static final String KEY_EXECUTE_TEXT_REPLY = "execute-command-reply";

static {
Expand Down Expand Up @@ -70,16 +71,19 @@ public void onCreate() {
createRunningNotification(),
ServiceInfo.FOREGROUND_SERVICE_TYPE_MANIFEST
);

thread = new NativeServerThread(this);
thread.start();
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if(intent != null) {
String action = intent.getAction();
if(INTENT_ACTION_EXECUTE.equals(action)) {
if(INTENT_ACTION_START.equals(action)) {
String[] commands = intent.getStringArrayExtra(INTENT_EXTRA_COMMANDS);
if(commands != null) {
thread = new NativeServerThread(this, commands);
thread.start();
}
} else if(INTENT_ACTION_EXECUTE.equals(action)) {
Bundle remoteInput = RemoteInput.getResultsFromIntent(intent);
if(remoteInput != null) {
CharSequence remoteCommand = remoteInput.getCharSequence(KEY_EXECUTE_TEXT_REPLY);
Expand All @@ -92,13 +96,18 @@ public int onStartCommand(Intent intent, int flags, int startId) {
notificationManager.notify(NOTIFICATION_ID, createRunningNotification());
}
} else {
String command = intent.getStringExtra(INTENT_EXTRA_COMMAND);
if(command != null) {
executeCommand(command);
String[] commands = intent.getStringArrayExtra(INTENT_EXTRA_COMMANDS);
if(commands != null) {
for(String command : commands) {
executeCommand(command);
}
}
}
}
}
if(thread == null) {
stopSelf();
}
return START_NOT_STICKY;
}

Expand Down Expand Up @@ -159,7 +168,7 @@ private Notification createRunningNotification() {

Intent stopIntent = new Intent(this, ServerService.class);
stopIntent.setAction(INTENT_ACTION_EXECUTE);
stopIntent.putExtra(INTENT_EXTRA_COMMAND, "shutdown");
stopIntent.putExtra(INTENT_EXTRA_COMMANDS, new String[] {"shutdown"});

PendingIntent stopActionIntent = PendingIntent.getService(
this,
Expand Down Expand Up @@ -241,6 +250,19 @@ private void executeCommand(String command) {
}
NativeServer.executeCommand(command);
}

public static Intent createStartIntent(Context context, String[] arguments) {
Intent intent = new Intent(context, ServerService.class);
intent.setAction(INTENT_ACTION_START);
intent.putExtra(INTENT_EXTRA_COMMANDS, arguments);
return intent;
}

public static Message createExecuteCommandMessage(String command) {
Message message = Message.obtain(null, MESSAGE_CODE_EXECUTE_COMMAND, 0, 0);
message.getData().putString(MESSAGE_EXTRA_COMMAND, command);
return message;
}
}

/**
Expand All @@ -251,9 +273,11 @@ private void executeCommand(String command) {
class NativeServerThread extends Thread {

private final Context applicationContext;
private final String[] arguments;

public NativeServerThread(Context context) {
public NativeServerThread(Context context, String[] arguments) {
this.applicationContext = context.getApplicationContext();
this.arguments = arguments;
}

@Override
Expand All @@ -267,7 +291,7 @@ public void run() {
return;
}

int Result = NativeServer.runServer(workingDirectory.getAbsolutePath());
int Result = NativeServer.runServer(workingDirectory.getAbsolutePath(), arguments);
new Handler(applicationContext.getMainLooper()).post(() -> {
if(Result != 0) {
Toast.makeText(applicationContext, applicationContext.getString(R.string.server_error_exit_code, Result), Toast.LENGTH_LONG).show();
Expand Down Expand Up @@ -297,9 +321,10 @@ private NativeServer() {
* exit code on completion.
*
* @param workingDirectory The working directory for the server, which must be the
* external storage directory of the app and already contains all data files.
* external storage directory of the app and already contain all data files.
* @param arguments Arguments to supply to the server when launching it.
*/
public static native int runServer(String workingDirectory);
public static native int runServer(String workingDirectory, String[] arguments);

/**
* Adds a command to the execution queue of the native server.
Expand Down
17 changes: 14 additions & 3 deletions src/android/android_main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@ void RestartAndroidApp()
SDL_AndroidSendMessage(COMMAND_RESTART_APP, 0);
}

bool StartAndroidServer()
bool StartAndroidServer(const char **ppArguments, size_t NumArguments)
{
// We need the notification-permission to show a notification for the foreground service.
// We use SDL for this instead of doing it on the Java side because this function blocks
Expand All @@ -252,9 +252,20 @@ bool StartAndroidServer()
jobject Activity = (jobject)SDL_AndroidGetActivity();
jclass ActivityClass = pEnv->GetObjectClass(Activity);

jmethodID MethodId = pEnv->GetMethodID(ActivityClass, "startServer", "()V");
pEnv->CallVoidMethod(Activity, MethodId);
jclass StringClass = pEnv->FindClass("java/lang/String");
jobjectArray ArgumentsArray = pEnv->NewObjectArray(NumArguments, StringClass, nullptr);
pEnv->DeleteLocalRef(StringClass);
for(size_t ArgumentIndex = 0; ArgumentIndex < NumArguments; ArgumentIndex++)
{
jstring ArgumentString = pEnv->NewStringUTF(ppArguments[ArgumentIndex]);
pEnv->SetObjectArrayElement(ArgumentsArray, ArgumentIndex, ArgumentString);
pEnv->DeleteLocalRef(ArgumentString);
}

jmethodID MethodId = pEnv->GetMethodID(ActivityClass, "startServer", "([Ljava/lang/String;)V");
pEnv->CallVoidMethod(Activity, MethodId, ArgumentsArray);

pEnv->DeleteLocalRef(ArgumentsArray);
pEnv->DeleteLocalRef(Activity);
pEnv->DeleteLocalRef(ActivityClass);

Expand Down
5 changes: 4 additions & 1 deletion src/android/android_main.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,12 @@ void RestartAndroidApp();
* This will request the notification-permission as it is required for
* foreground services to show a notification.
*
* @param ppArguments Array of arguments to pass to the server on launch.
* @param NumArguments The number of arguments.
*
* @return `true` on success, `false` on error.
*/
bool StartAndroidServer();
bool StartAndroidServer(const char **ppArguments, size_t NumArguments);

/**
* Adds a command to the execution queue of the local server.
Expand Down
25 changes: 22 additions & 3 deletions src/engine/server/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,7 @@ std::vector<std::string> FetchAndroidServerCommandQueue()
return vResult;
}

JNI_EXPORTED_FUNCTION(ANDROID_PACKAGE_NAME, NativeServer, runServer, jint, JNIEnv *pEnv, jobject Object, jstring WorkingDirectory)
JNI_EXPORTED_FUNCTION(ANDROID_PACKAGE_NAME, NativeServer, runServer, jint, JNIEnv *pEnv, jobject Object, jstring WorkingDirectory, jobjectArray ArgumentsArray)
{
// Set working directory to external storage location. This is not possible
// in Java so we pass the intended working directory to the native code.
Expand All @@ -248,8 +248,27 @@ JNI_EXPORTED_FUNCTION(ANDROID_PACKAGE_NAME, NativeServer, runServer, jint, JNIEn
return -1001;
}

const char *apArgs[] = {GAME_NAME};
return main(std::size(apArgs), apArgs);
const jsize NumArguments = pEnv->GetArrayLength(ArgumentsArray);

std::vector<std::string> vArguments;
vArguments.reserve(NumArguments + 1);
vArguments.push_back(std::string(pWorkingDirectory) + "/" + GAME_NAME "-Server");
for(jsize ArgumentIndex = 0; ArgumentIndex < NumArguments; ArgumentIndex++)
{
jstring ArgumentString = (jstring)pEnv->GetObjectArrayElement(ArgumentsArray, ArgumentIndex);
const char *pArgumentString = pEnv->GetStringUTFChars(ArgumentString, nullptr);
vArguments.emplace_back(pArgumentString);
pEnv->ReleaseStringUTFChars(ArgumentString, pArgumentString);
}

std::vector<const char *> vpArguments;
vpArguments.reserve(vArguments.size());
for(const std::string &Argument : vArguments)
{
vpArguments.emplace_back(Argument.c_str());
}

return main(vpArguments.size(), vpArguments.data());
}

JNI_EXPORTED_FUNCTION(ANDROID_PACKAGE_NAME, NativeServer, executeCommand, void, JNIEnv *pEnv, jobject Object, jstring Command)
Expand Down
2 changes: 1 addition & 1 deletion src/game/client/components/menus_start.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,7 @@ void CMenus::RenderStartMenu(CUIRect MainView)
void CMenus::RunServer()
{
#if defined(CONF_PLATFORM_ANDROID)
if(StartAndroidServer())
if(StartAndroidServer({}, 0))
{
m_ForceRefreshLanPage = true;
}
Expand Down

0 comments on commit 24d9705

Please sign in to comment.