Update Android port

* 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.
This commit is contained in:
Po Lu 2023-05-31 10:13:04 +08:00
parent 733a6776f9
commit 57903519eb
6 changed files with 126 additions and 22 deletions

View file

@ -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

View 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

View 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 @@ invocation of app_process (through android-emacs) can
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

View file

@ -628,8 +628,14 @@ else if (child.getVisibility () != GONE)
}
/* 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: "

View file

@ -6959,8 +6959,11 @@ android_display_toast (const char *text)
/* 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;
}

View 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. */