Browse Source

android: enable writing stdout/stderr to a socket

This can be done by setting the extra string org.panda3d.OUTPUT_URI to tcp://host:port
Writing to a log file can still be done using file:///path/to/log.txt

[skip ci]
rdb 7 years ago
parent
commit
8e8283cbe1

+ 2 - 2
panda/src/android/PandaActivity.java

@@ -87,9 +87,9 @@ public class PandaActivity extends NativeActivity {
         return path;
     }
 
-    public String getIntentOutputPath() {
+    public String getIntentOutputUri() {
         Intent intent = getIntent();
-        return intent.getStringExtra("org.panda3d.OUTPUT_PATH");
+        return intent.getStringExtra("org.panda3d.OUTPUT_URI");
     }
 
     public String getCacheDirString() {

+ 55 - 22
panda/src/android/android_main.cxx

@@ -17,11 +17,14 @@
 #include "virtualFileSystem.h"
 #include "filename.h"
 #include "thread.h"
+#include "urlSpec.h"
 
 #include "config_display.h"
 // #define OPENGLES_1 #include "config_androiddisplay.h"
 
 #include <android_native_app_glue.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
 
 // struct android_app* panda_android_app = NULL;
 
@@ -67,6 +70,55 @@ void android_main(struct android_app* app) {
   android_cat.info()
     << "New native activity started on " << *current_thread << "\n";
 
+  // Were we given an optional location to write the stdout/stderr streams?
+  methodID = env->GetMethodID(activity_class, "getIntentOutputUri", "()Ljava/lang/String;");
+  jstring joutput_uri = (jstring) env->CallObjectMethod(activity->clazz, methodID);
+  if (joutput_uri != nullptr) {
+    const char *output_uri = env->GetStringUTFChars(joutput_uri, nullptr);
+
+    if (output_uri != nullptr && output_uri[0] != 0) {
+      URLSpec spec(output_uri);
+
+      if (spec.get_scheme() == "file") {
+        string path = spec.get_path();
+        int fd = open(path.c_str(), O_CREAT | O_TRUNC | O_WRONLY);
+        if (fd != -1) {
+          android_cat.info()
+            << "Writing standard output to file " << path << "\n";
+
+          dup2(fd, 1);
+          dup2(fd, 2);
+        } else {
+          android_cat.error()
+            << "Failed to open output path " << path << "\n";
+        }
+      } else if (spec.get_scheme() == "tcp") {
+        string host = spec.get_server();
+        int fd = socket(AF_INET, SOCK_STREAM, 0);
+        struct sockaddr_in serv_addr = {0};
+        serv_addr.sin_family = AF_INET;
+        serv_addr.sin_port = htons(spec.get_port());
+        serv_addr.sin_addr.s_addr = inet_addr(host.c_str());
+        if (connect(fd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) == 0) {
+          android_cat.info()
+            << "Writing standard output to socket "
+            << spec.get_server_and_port() << "\n";
+          dup2(fd, 1);
+          dup2(fd, 2);
+        } else {
+          android_cat.error()
+            << "Failed to open output socket "
+            << spec.get_server_and_port() << "\n";
+        }
+        close(fd);
+      } else {
+        android_cat.error()
+          << "Unsupported scheme in output URI: " << output_uri << "\n";
+      }
+      env->ReleaseStringUTFChars(joutput_uri, output_uri);
+    }
+  }
+
   // Fetch the data directory.
   jmethodID get_appinfo = env->GetMethodID(activity_class, "getApplicationInfo", "()Landroid/content/pm/ApplicationInfo;");
 
@@ -186,28 +238,6 @@ void android_main(struct android_app* app) {
     }
   }
 
-  // Were we given an optional location to write the stdout/stderr streams?
-  methodID = env->GetMethodID(activity_class, "getIntentOutputPath", "()Ljava/lang/String;");
-  jstring joutput_path = (jstring) env->CallObjectMethod(activity->clazz, methodID);
-  if (joutput_path != nullptr) {
-    const char *output_path = env->GetStringUTFChars(joutput_path, nullptr);
-
-    if (output_path != nullptr && output_path[0] != 0) {
-      int fd = open(output_path, O_CREAT | O_TRUNC | O_WRONLY);
-      if (fd != -1) {
-        android_cat.info()
-          << "Writing standard output to file " << output_path << "\n";
-
-        dup2(fd, 1);
-        dup2(fd, 2);
-      } else {
-        android_cat.error()
-          << "Failed to open output path " << output_path << "\n";
-      }
-      env->ReleaseStringUTFChars(joutput_path, output_path);
-    }
-  }
-
   // Create bogus argc and argv for calling the main function.
   const char *argv[] = {"pview", nullptr, nullptr};
   int argc = 1;
@@ -266,6 +296,9 @@ void android_main(struct android_app* app) {
     env->ReleaseStringUTFChars(filename, filename_str);
   }
 
+  close(1);
+  close(2);
+
   // Detach the thread before exiting.
   activity->vm->DetachCurrentThread();
 }

+ 1 - 0
panda/src/android/pview_manifest.xml

@@ -7,6 +7,7 @@
 
     <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+    <uses-permission android:name="android.permission.INTERNET" />
     <uses-sdk android:minSdkVersion="21" />
     <uses-feature android:glEsVersion="0x00020000" android:required="true" />