]> git.eshelyaron.com Git - emacs.git/commitdiff
Update Android port
authorPo Lu <luangruo@yahoo.com>
Wed, 25 Jan 2023 14:07:51 +0000 (22:07 +0800)
committerPo Lu <luangruo@yahoo.com>
Wed, 25 Jan 2023 14:07:51 +0000 (22:07 +0800)
* 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
java/org/gnu/emacs/EmacsNoninteractive.java
java/org/gnu/emacs/EmacsSdk11Clipboard.java
java/org/gnu/emacs/EmacsService.java
src/alloc.c
src/android-emacs.c
src/android.c
src/callproc.c

index 717e2279a7d3adefa8fcf9f5e948c52612c9c3eb..c6e5123bfcadc5bdef52ca6fa4a2ad0aabd5ec78 100644 (file)
@@ -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);
 
index a3aefee5e0b81f11fa47e42e654fb1e050486b96..b4854d8323fe995571a4ac80d33aeeece9a236ec 100644 (file)
@@ -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.  */
index 0a725200723f3e7afc08a858f1d5e04c560a44b5..2df2015c9c1bee0f1f3a12e50d284271cea496c7 100644 (file)
@@ -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);
   }
 
index 91db76b08e3c3a598774d8daf0406bae92834841..eb9b61dd8764309e1b1a89c20229492b0bfeca80 100644 (file)
@@ -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;
+  }
 };
index ed55ae32710b102fcd7b30c24752dffba412a666..bc43f22005de6779afb85e375d83aa882d3d2fe3 100644 (file)
@@ -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++)
index c1f2a6f43bbd51bff0fcf5f5811aaa7eea144b4c..e64caf9a9d4f86e93a762f180d68874145567184 100644 (file)
@@ -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);
index 8c4442e339799ffc4982a2126c11f1b8b41bf520..2f21a03b53fd8f044a0b59a23c678e9c925dd812 100644 (file)
@@ -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;
+
 \f
 
 /* 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);
index 85895a7d9f21bb45216ac0444890af1aa76c4d71..e15eebe23dd1157dcde52901af45adeeced5988e 100644 (file)
@@ -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)