Skip to content

Commit

Permalink
Support passing launch arguments to Android server
Browse files Browse the repository at this point in the history
Currently no arguments are passed when launching the server though, this is for supporting 9092.
  • Loading branch information
Robyt3 committed Jan 3, 2025
1 parent 3988f32 commit 852aa37
Show file tree
Hide file tree
Showing 6 changed files with 82 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
54 changes: 38 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,16 @@ 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)) {
thread = new NativeServerThread(this, intent.getStringArrayExtra(INTENT_EXTRA_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 +93,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 +165,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 +247,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 +270,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 +288,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 +318,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(NumArguments);
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 852aa37

Please sign in to comment.