]> git.eshelyaron.com Git - emacs.git/commitdiff
Update Android port
authorPo Lu <luangruo@yahoo.com>
Wed, 31 May 2023 02:13:04 +0000 (10:13 +0800)
committerPo Lu <luangruo@yahoo.com>
Wed, 31 May 2023 02:13:04 +0000 (10:13 +0800)
* java/debug.sh (is_root): Go back to using unix sockets; allow
adb to forward them correctly.
* java/org/gnu/emacs/EmacsInputConnection.java
(getExtractedText): Don't print text if NULL.
* java/org/gnu/emacs/EmacsService.java (EmacsService): New field
`imSyncInProgress'.
(updateIC): If an IM sync might be in progress, avoid deadlocks.
* java/org/gnu/emacs/EmacsView.java (onCreateInputConnection):
Set `imSyncInProgress' across synchronization point.
* src/android.c (android_check_query): Use __atomic_store_n.
(android_answer_query): New function.
(android_begin_query): Set `android_servicing_query' to 2.
Check once, and don't spin waiting for query to complete.
(android_end_query): Use __atomic_store_n.
(android_run_in_emacs_thread): Compare-and-exchange flag.  If
originally 1, fail.
* src/textconv.c (really_set_composing_text): Clear conversion
region if text is empty.

java/debug.sh
java/org/gnu/emacs/EmacsInputConnection.java
java/org/gnu/emacs/EmacsService.java
java/org/gnu/emacs/EmacsView.java
src/android.c
src/textconv.c

index 339b3604810cc3c2b3903ae4a54c0bd7c81b9fd9..0458003fe72b66d9709710ac112be443f7a4a48b 100755 (executable)
@@ -19,6 +19,7 @@
 ## along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
 
 set -m
+set -x
 oldpwd=`pwd`
 cd `dirname $0`
 
@@ -310,22 +311,26 @@ rm -f /tmp/file-descriptor-stamp
 
 if [ -z "$gdbserver" ]; then
     if [ "$is_root" = "yes" ]; then
-       adb -s $device shell $gdbserver_bin --once \
+       adb -s $device shell $gdbserver_bin --multi \
            "+/data/local/tmp/debug.$package.socket" --attach $pid >&5 &
        gdb_socket="localfilesystem:/data/local/tmp/debug.$package.socket"
-    else       
-       adb -s $device shell run-as $package $gdbserver_bin --once \
+    else
+       adb -s $device shell run-as $package $gdbserver_bin --multi \
            "+debug.$package.socket" --attach $pid >&5 &
        gdb_socket="localfilesystem:$app_data_dir/debug.$package.socket"
     fi
 else
     # Normally the program cannot access $gdbserver_bin when it is
     # placed in /data/local/tmp.
-    adb -s $device shell run-as $package $gdbserver_cmd --once \
-       "0.0.0.0:7654" --attach $pid >&5 &
-    gdb_socket="tcp:7654"
+    adb -s $device shell run-as $package $gdbserver_cmd --multi \
+       "+debug.$package.socket" --attach $pid >&5 &
+    gdb_socket="localfilesystem:$app_data_dir/debug.$package.socket"
 fi
 
+# In order to allow adb to forward to the gdbserver socket, make the
+# app data directory a+x.
+adb -s $device shell run-as $package chmod a+x $app_data_dir
+
 # Wait until gdbserver successfully runs.
 line=
 while read -u 5 line; do
index 21bbaca5d075acfc30b4c2a5e79c317db82c0cf6..420da58c0f8b8d8e1e9200ad9cd7dd9d86e27dfe 100644 (file)
@@ -286,6 +286,14 @@ public final class EmacsInputConnection extends BaseInputConnection
       text = EmacsNative.getExtractedText (windowHandle, request,
                                           flags);
 
+    if (text == null)
+      {
+       if (EmacsService.DEBUG_IC)
+         Log.d (TAG, "getExtractedText: text is NULL");
+
+       return null;
+      }
+
     if (EmacsService.DEBUG_IC)
       Log.d (TAG, "getExtractedText: " + text.text + " @"
             + text.startOffset + ":" + text.selectionStart
index 546d22627c571de50f16daf2bb9c7f8fbaa83220..2f35933a7d159752bc244b0686f19a0b9a66e634 100644 (file)
@@ -104,6 +104,9 @@ public final class EmacsService extends Service
      performing drawing calls.  */
   private static final boolean DEBUG_THREADS = false;
 
+  /* Whether or not onCreateInputMethod is calling getSelection.  */
+  public static volatile boolean imSyncInProgress;
+
   /* Return the directory leading to the directory in which native
      library files are stored on behalf of CONTEXT.  */
 
@@ -636,16 +639,41 @@ public final class EmacsService extends Service
            int newSelectionEnd, int composingRegionStart,
            int composingRegionEnd)
   {
+    boolean wasSynchronous;
+
     if (DEBUG_IC)
       Log.d (TAG, ("updateIC: " + window + " " + newSelectionStart
                   + " " + newSelectionEnd + " "
                   + composingRegionStart + " "
                   + composingRegionEnd));
+
+    /* `updateSelection' holds an internal lock that is also taken
+       before `onCreateInputConnection' (in EmacsView.java) is called;
+       when that then asks the UI thread for the current selection, a
+       dead lock results.  To remedy this, reply to any synchronous
+       queries now -- and prohibit more queries for the duration of
+       `updateSelection' -- if EmacsView may have been asking for the
+       value of the region.  */
+
+    wasSynchronous = false;
+    if (EmacsService.imSyncInProgress)
+      {
+       /* `beginSynchronous' will answer any outstanding queries and
+          signal that one is now in progress, thereby preventing
+          `getSelection' from blocking.  */
+
+       EmacsNative.beginSynchronous ();
+       wasSynchronous = true;
+      }
+
     window.view.imManager.updateSelection (window.view,
                                           newSelectionStart,
                                           newSelectionEnd,
                                           composingRegionStart,
                                           composingRegionEnd);
+
+    if (wasSynchronous)
+      EmacsNative.endSynchronous ();
   }
 
   public void
index 09bc9d719d3bbfa281d4045af446e89f27b6656d..bb450bb8e6b9fdfbd296e1d18165a1e9a5d35ed0 100644 (file)
@@ -628,8 +628,14 @@ public final class EmacsView extends ViewGroup
       }
 
     /* Obtain the current position of point and set it as the
-       selection.  */
+       selection.  Don't do this under one specific situation: if
+       `android_update_ic' is being called in the main thread, trying
+       to synchronize with it can cause a dead lock in the IM
+       manager.  */
+
+    EmacsService.imSyncInProgress = true;
     selection = EmacsNative.getSelection (window.handle);
+    EmacsService.imSyncInProgress = false;
 
     if (selection != null)
       Log.d (TAG, "onCreateInputConnection: current selection is: "
index 8cc187873589549e7a90a8181de215fd95508095..9d1399f3fc24669aef53fb0cd73631669c88ff21 100644 (file)
@@ -6959,8 +6959,11 @@ android_display_toast (const char *text)
 
 \f
 
-/* Whether or not a query is currently being made.  */
-static bool android_servicing_query;
+/* The thread from which a query against a thread is currently being
+   made, if any.  Value is 0 if no query is in progress, 1 if a query
+   is being made from the UI thread to the main thread, and 2 if a
+   query is being made the other way around.  */
+static char android_servicing_query;
 
 /* Function that is waiting to be run in the Emacs thread.  */
 static void (*android_query_function) (void *);
@@ -7010,7 +7013,37 @@ android_check_query (void)
   /* Finish the query.  */
   __atomic_store_n (&android_query_context, NULL, __ATOMIC_SEQ_CST);
   __atomic_store_n (&android_query_function, NULL, __ATOMIC_SEQ_CST);
-  __atomic_clear (&android_servicing_query, __ATOMIC_SEQ_CST);
+  __atomic_store_n (&android_servicing_query, 0, __ATOMIC_SEQ_CST);
+
+  /* Signal completion.  */
+  sem_post (&android_query_sem);
+}
+
+/* Run the function that the UI thread has asked to run, and then
+   signal its completion.  Do not change `android_servicing_query'
+   after it completes.  */
+
+static void
+android_answer_query (void)
+{
+  void (*proc) (void *);
+  void *closure;
+
+  eassert (__atomic_load_n (&android_servicing_query, __ATOMIC_SEQ_CST)
+          == 1);
+
+  /* First, load the procedure and closure.  */
+  __atomic_load (&android_query_context, &closure, __ATOMIC_SEQ_CST);
+  __atomic_load (&android_query_function, &proc, __ATOMIC_SEQ_CST);
+
+  if (!proc)
+    return;
+
+  proc (closure);
+
+  /* Finish the query.  */
+  __atomic_store_n (&android_query_context, NULL, __ATOMIC_SEQ_CST);
+  __atomic_store_n (&android_query_function, NULL, __ATOMIC_SEQ_CST);
 
   /* Signal completion.  */
   sem_post (&android_query_sem);
@@ -7025,18 +7058,23 @@ android_check_query (void)
 static void
 android_begin_query (void)
 {
-  if (__atomic_test_and_set (&android_servicing_query,
-                            __ATOMIC_SEQ_CST))
+  char old;
+
+  /* Load the previous value of `android_servicing_query' and upgrade
+     it to 2.  */
+
+  old = __atomic_exchange_n (&android_servicing_query,
+                            2, __ATOMIC_SEQ_CST);
+
+  /* See if a query was previously in progress.  */
+  if (old == 1)
     {
       /* Answer the query that is currently being made.  */
       assert (android_query_function != NULL);
-      android_check_query ();
-
-      /* Wait for that query to complete.  */
-      while (__atomic_load_n (&android_servicing_query,
-                             __ATOMIC_SEQ_CST))
-       ;;
+      android_answer_query ();
     }
+
+  /* `android_servicing_query' is now 2.  */
 }
 
 /* Notice that a query has stopped.  This function may be called from
@@ -7045,7 +7083,7 @@ android_begin_query (void)
 static void
 android_end_query (void)
 {
-  __atomic_clear (&android_servicing_query, __ATOMIC_SEQ_CST);
+  __atomic_store_n (&android_servicing_query, 0, __ATOMIC_SEQ_CST);
 }
 
 /* Synchronously ask the Emacs thread to run the specified PROC with
@@ -7063,6 +7101,7 @@ int
 android_run_in_emacs_thread (void (*proc) (void *), void *closure)
 {
   union android_event event;
+  char old;
 
   event.xaction.type = ANDROID_WINDOW_ACTION;
   event.xaction.serial = ++event_serial;
@@ -7074,10 +7113,13 @@ android_run_in_emacs_thread (void (*proc) (void *), void *closure)
   __atomic_store_n (&android_query_function, proc, __ATOMIC_SEQ_CST);
 
   /* Don't allow deadlocks to happen; make sure the Emacs thread is
-     not waiting for something to be done.  */
+     not waiting for something to be done (in that case,
+     `android_query_context' is 2.)  */
 
-  if (__atomic_test_and_set (&android_servicing_query,
-                            __ATOMIC_SEQ_CST))
+  old = 0;
+  if (!__atomic_compare_exchange_n (&android_servicing_query, &old,
+                                   1, false, __ATOMIC_SEQ_CST,
+                                   __ATOMIC_SEQ_CST))
     {
       __atomic_store_n (&android_query_context, NULL,
                        __ATOMIC_SEQ_CST);
@@ -7098,6 +7140,15 @@ android_run_in_emacs_thread (void (*proc) (void *), void *closure)
   while (sem_wait (&android_query_sem) < 0)
     ;;
 
+  /* At this point, `android_servicing_query' should either be zero if
+     the query was answered or two if the main thread has started a
+     query.  */
+
+  eassert (!__atomic_load_n (&android_servicing_query,
+                           __ATOMIC_SEQ_CST)
+          || (__atomic_load_n (&android_servicing_query,
+                               __ATOMIC_SEQ_CST) == 2));
+
   return 0;
 }
 
index 26f351dc72923fad58126d369a6f0362dee395f0..1530cc0ce320093fc557c8334d2dd4e46b634d79 100644 (file)
@@ -792,6 +792,12 @@ really_set_composing_text (struct frame *f, ptrdiff_t position,
   /* Move the composition overlay.  */
   sync_overlay (f);
 
+  /* If TEXT is empty, remove the composing region.  This goes against
+     the documentation, but is ultimately what programs expect.  */
+
+  if (!SCHARS (text))
+    really_finish_composing_text (f);
+
   /* If PT hasn't changed, the conversion region definitely has.
      Otherwise, redisplay will update the input method instead.  */