emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

feature/android 0b1ef9ea31 3/5: Update Android port


From: Po Lu
Subject: feature/android 0b1ef9ea31 3/5: Update Android port
Date: Thu, 26 Jan 2023 02:37:43 -0500 (EST)

branch: feature/android
commit 0b1ef9ea31ce039001546b3ed34494332e5e3629
Author: Po Lu <luangruo@yahoo.com>
Commit: Po Lu <luangruo@yahoo.com>

    Update Android port
    
    * java/org/gnu/emacs/EmacsDrawLine.java: Fix this again.  Gosh,
    how does Android do this.
    * java/org/gnu/emacs/EmacsNoninteractive.java (main): Port to
    Android 2.3.3.
    
    * java/org/gnu/emacs/EmacsSdk11Clipboard.java
    (EmacsSdk11Clipboard): Port to Android 4.0.3.
    * java/org/gnu/emacs/EmacsService.java (getClipboardManager):
    New function.
    
    * src/alloc.c (find_string_data_in_pure): Fix Android alignment
    issue.
    
    * src/android-emacs.c (main): Port to Android 4.4.
    * src/android.c (initEmacs): Align stack to 32 bytes, so it ends
    up aligned to 16 even though gcc thinks the stack is already
    aligned to 16 bytes.
    
    * src/callproc.c (init_callproc): Use /system/bin/sh instead of
    /bin/sh by default.
---
 java/org/gnu/emacs/EmacsDrawLine.java       |  2 +-
 java/org/gnu/emacs/EmacsNoninteractive.java | 30 +++++++--
 java/org/gnu/emacs/EmacsSdk11Clipboard.java |  8 +--
 java/org/gnu/emacs/EmacsService.java        | 46 ++++++++++++++
 src/alloc.c                                 | 16 +++++
 src/android-emacs.c                         | 94 ++++++++++++++++++++++++-----
 src/android.c                               | 14 +++++
 src/callproc.c                              |  5 ++
 8 files changed, 186 insertions(+), 29 deletions(-)

diff --git a/java/org/gnu/emacs/EmacsDrawLine.java 
b/java/org/gnu/emacs/EmacsDrawLine.java
index 717e2279a7..c6e5123bfc 100644
--- a/java/org/gnu/emacs/EmacsDrawLine.java
+++ b/java/org/gnu/emacs/EmacsDrawLine.java
@@ -60,7 +60,7 @@ public class EmacsDrawLine
        coordinates appropriately.  */
 
     if (gc.clip_mask == null)
-      canvas.drawLine ((float) x + 0.5f, (float) y + 0.5f,
+      canvas.drawLine ((float) x, (float) y + 0.5f,
                       (float) x2 + 0.5f, (float) y2 + 0.5f,
                       paint);
 
diff --git a/java/org/gnu/emacs/EmacsNoninteractive.java 
b/java/org/gnu/emacs/EmacsNoninteractive.java
index a3aefee5e0..b4854d8323 100644
--- a/java/org/gnu/emacs/EmacsNoninteractive.java
+++ b/java/org/gnu/emacs/EmacsNoninteractive.java
@@ -95,7 +95,7 @@ public class EmacsNoninteractive
           On Android 2.3.3 and earlier, there is no
           ``compatibilityInfo'' argument to getPackageInfo.  */
 
-       if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.GINGERBREAD)
+       if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.GINGERBREAD_MR1)
          {
            method
              = activityThreadClass.getMethod ("getPackageInfo",
@@ -123,11 +123,29 @@ public class EmacsNoninteractive
 
        /* Now, get a context.  */
        contextImplClass = Class.forName ("android.app.ContextImpl");
-       method = contextImplClass.getDeclaredMethod ("createAppContext",
-                                                    activityThreadClass,
-                                                    loadedApkClass);
-       method.setAccessible (true);
-       context = (Context) method.invoke (null, activityThread, loadedApk);
+
+       try
+         {
+           method = contextImplClass.getDeclaredMethod ("createAppContext",
+                                                        activityThreadClass,
+                                                        loadedApkClass);
+           method.setAccessible (true);
+           context = (Context) method.invoke (null, activityThread, loadedApk);
+         }
+       catch (NoSuchMethodException exception)
+         {
+           /* Older Android versions don't have createAppContext, but
+              instead require creating a ContextImpl, and then
+              calling createPackageContext.  */
+           method = activityThreadClass.getDeclaredMethod ("getSystemContext");
+           context = (Context) method.invoke (activityThread);
+           method = contextImplClass.getDeclaredMethod ("createPackageContext",
+                                                        String.class,
+                                                        int.class);
+           method.setAccessible (true);
+           context = (Context) method.invoke (context, "org.gnu.emacs",
+                                              0);
+         }
 
        /* Don't actually start the looper or anything.  Instead, obtain
           an AssetManager.  */
diff --git a/java/org/gnu/emacs/EmacsSdk11Clipboard.java 
b/java/org/gnu/emacs/EmacsSdk11Clipboard.java
index 0a72520072..2df2015c9c 100644
--- a/java/org/gnu/emacs/EmacsSdk11Clipboard.java
+++ b/java/org/gnu/emacs/EmacsSdk11Clipboard.java
@@ -42,13 +42,7 @@ public class EmacsSdk11Clipboard extends EmacsClipboard
   public
   EmacsSdk11Clipboard ()
   {
-    String what;
-    Context context;
-
-    what = Context.CLIPBOARD_SERVICE;
-    context = EmacsService.SERVICE;
-    manager
-      = (ClipboardManager) context.getSystemService (what);
+    manager = EmacsService.SERVICE.getClipboardManager ();
     manager.addPrimaryClipChangedListener (this);
   }
 
diff --git a/java/org/gnu/emacs/EmacsService.java 
b/java/org/gnu/emacs/EmacsService.java
index 91db76b08e..eb9b61dd87 100644
--- a/java/org/gnu/emacs/EmacsService.java
+++ b/java/org/gnu/emacs/EmacsService.java
@@ -39,6 +39,7 @@ import android.app.NotificationChannel;
 import android.app.PendingIntent;
 import android.app.Service;
 
+import android.content.ClipboardManager;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.ApplicationInfo;
@@ -565,4 +566,49 @@ public class EmacsService extends Service
 
     return null;
   }
+
+  /* Get a SDK 11 ClipboardManager.
+
+     Android 4.0.x requires that this be called from the main
+     thread.  */
+
+  public ClipboardManager
+  getClipboardManager ()
+  {
+    final Holder<ClipboardManager> manager;
+    Runnable runnable;
+
+    manager = new Holder<ClipboardManager> ();
+
+    runnable = new Runnable () {
+       public void
+       run ()
+       {
+         Object tem;
+
+         synchronized (this)
+           {
+             tem = getSystemService (Context.CLIPBOARD_SERVICE);
+             manager.thing = (ClipboardManager) tem;
+             notify ();
+           }
+       }
+      };
+
+    synchronized (runnable)
+      {
+       runOnUiThread (runnable);
+
+       try
+         {
+           runnable.wait ();
+         }
+       catch (InterruptedException e)
+         {
+           EmacsNative.emacsAbort ();
+         }
+      }
+
+    return manager.thing;
+  }
 };
diff --git a/src/alloc.c b/src/alloc.c
index ed55ae3271..bc43f22005 100644
--- a/src/alloc.c
+++ b/src/alloc.c
@@ -5662,6 +5662,22 @@ find_string_data_in_pure (const char *data, ptrdiff_t 
nbytes)
   if (pure_bytes_used_non_lisp <= nbytes)
     return NULL;
 
+  /* The Android GCC generates code like:
+
+   0xa539e755 <+52>:   lea    0x430(%esp),%esi
+=> 0xa539e75c <+59>:   movdqa %xmm0,0x0(%ebp)
+   0xa539e761 <+64>:   add    $0x10,%ebp
+
+   but data is not aligned appropriately, so a GP fault results.  */
+
+#if defined __i386__                           \
+  && defined HAVE_ANDROID                      \
+  && !defined ANDROID_STUBIFY                  \
+  && !defined (__clang__)
+  if ((intptr_t) data & 15)
+    return NULL;
+#endif
+
   /* Set up the Boyer-Moore table.  */
   skip = nbytes + 1;
   for (i = 0; i < 256; i++)
diff --git a/src/android-emacs.c b/src/android-emacs.c
index c1f2a6f43b..e64caf9a9d 100644
--- a/src/android-emacs.c
+++ b/src/android-emacs.c
@@ -52,12 +52,37 @@ main (int argc, char **argv)
   args[0] = (char *) "/system/bin/app_process";
 #endif
 
+  /* Machines with ART require the boot classpath to be manually
+     specified.  Machines with Dalvik however refuse to do so, as they
+     open the jars inside the BOOTCLASSPATH environment variable at
+     startup, resulting in the following crash:
+
+     W/dalvikvm( 1608): Refusing to reopen boot DEX
+     '/system/framework/core.jar'
+     W/dalvikvm( 1608): Refusing to reopen boot DEX
+     '/system/framework/bouncycastle.jar'
+     E/dalvikvm( 1608): Too many exceptions during init (failed on
+     'Ljava/io/IOException;' 'Re-opening BOOTCLASSPATH DEX files is
+     not allowed')
+     E/dalvikvm( 1608): VM aborting  */
+
+#if HAVE_DECL_ANDROID_GET_DEVICE_API_LEVEL
+  if (android_get_device_api_level () < 21)
+    {
+      bootclasspath = NULL;
+      goto skip_setup;
+    }
+#else
+  if (__ANDROID_API__ < 21)
+    {
+      bootclasspath = NULL;
+      goto skip_setup;
+    }
+#endif
+
   /* Next, obtain the boot class path.  */
   bootclasspath = getenv ("BOOTCLASSPATH");
 
-  /* And the Emacs class path.  */
-  emacs_class_path = getenv ("EMACS_CLASS_PATH");
-
   if (!bootclasspath)
     {
       fprintf (stderr, "The BOOTCLASSPATH environment variable"
@@ -68,6 +93,11 @@ main (int argc, char **argv)
       return 1;
     }
 
+ skip_setup:
+
+  /* And the Emacs class path.  */
+  emacs_class_path = getenv ("EMACS_CLASS_PATH");
+
   if (!emacs_class_path)
     {
       fprintf (stderr, "EMACS_CLASS_PATH not set."
@@ -76,25 +106,59 @@ main (int argc, char **argv)
       return 1;
     }
 
-  if (asprintf (&bootclasspath, "-Djava.class.path=%s:%s",
-               bootclasspath, emacs_class_path) < 0)
+  if (bootclasspath)
     {
-      perror ("asprintf");
-      return 1;
+      if (asprintf (&bootclasspath, "-Djava.class.path=%s:%s",
+                   bootclasspath, emacs_class_path) < 0)
+       {
+         perror ("asprintf");
+         return 1;
+       }
+    }
+  else
+    {
+      if (asprintf (&bootclasspath, "-Djava.class.path=%s",
+                   emacs_class_path) < 0)
+       {
+         perror ("asprintf");
+         return 1;
+       }
     }
 
   args[1] = bootclasspath;
   args[2] = (char *) "/system/bin";
-  args[3] = (char *) "--nice-name=emacs";
-  args[4] = (char *) "org.gnu.emacs.EmacsNoninteractive";
 
-  /* Arguments from here on are passed to main in
-     EmacsNoninteractive.java.  */
-  args[5] = argv[0];
+#if HAVE_DECL_ANDROID_GET_DEVICE_API_LEVEL
+  /* I don't know exactly when --nice-name was introduced; this is
+     just a guess.  */
+  if (android_get_device_api_level () >= 26)
+    {
+      args[3] = (char *) "--nice-name=emacs";
+      args[4] = (char *) "org.gnu.emacs.EmacsNoninteractive";
+
+      /* Arguments from here on are passed to main in
+        EmacsNoninteractive.java.  */
+      args[5] = argv[0];
 
-  /* Now copy the rest of the arguments over.  */
-  for (i = 1; i < argc; ++i)
-    args[5 + i] = argv[i];
+      /* Now copy the rest of the arguments over.  */
+      for (i = 1; i < argc; ++i)
+       args[5 + i] = argv[i];
+    }
+  else
+    {
+#endif
+      args[3] = (char *) "org.gnu.emacs.EmacsNoninteractive";
+
+      /* Arguments from here on are passed to main in
+        EmacsNoninteractive.java.  */
+      args[4] = argv[0];
+
+      /* Now copy the rest of the arguments over.  */
+      for (i = 1; i < argc; ++i)
+       args[4 + i] = argv[i];
+#if HAVE_DECL_ANDROID_GET_DEVICE_API_LEVEL
+    }
+#endif
 
   /* Finally, try to start the app_process.  */
   execvp (args[0], args);
diff --git a/src/android.c b/src/android.c
index 8c4442e339..2f21a03b53 100644
--- a/src/android.c
+++ b/src/android.c
@@ -205,6 +205,9 @@ static struct android_emacs_window window_class;
    stored in unsigned long to be consistent with X.  */
 static unsigned int event_serial;
 
+/* Unused pointer used to control compiler optimizations.  */
+void *unused_pointer;
+
 
 
 /* Event handling functions.  Events are stored on a (circular) queue
@@ -1718,6 +1721,17 @@ NATIVE_NAME (initEmacs) (JNIEnv *env, jobject object, 
jarray argv,
   const char *c_argument;
   char *dump_file;
 
+  /* android_emacs_init is not main, so GCC is not nice enough to add
+     the stack alignment prologue.
+
+     Unfortunately for us, dalvik on Android 4.0.x calls native code
+     with a 4 byte aligned stack.  */
+
+  __attribute__ ((aligned (32))) char buffer[32];
+
+  /* Trick GCC into not optimizing this variable away.  */
+  unused_pointer = buffer;
+
   android_java_env = env;
 
   nelements = (*env)->GetArrayLength (env, argv);
diff --git a/src/callproc.c b/src/callproc.c
index 85895a7d9f..e15eebe23d 100644
--- a/src/callproc.c
+++ b/src/callproc.c
@@ -1987,7 +1987,12 @@ init_callproc (void)
     dir_warning ("arch-independent data dir", Vdata_directory);
 
   sh = getenv ("SHELL");
+#if defined HAVE_ANDROID && !defined ANDROID_STUBIFY
+  /* The Android shell is found under /system/bin, not /bin.  */
+  Vshell_file_name = build_string (sh ? sh : "/system/bin/sh");
+#else
   Vshell_file_name = build_string (sh ? sh : "/bin/sh");
+#endif
 
   Lisp_Object gamedir = Qnil;
   if (PATH_GAME)



reply via email to

[Prev in Thread] Current Thread [Next in Thread]