aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorPo Lu2023-02-17 16:27:00 +0800
committerPo Lu2023-02-17 16:27:00 +0800
commit88afd96e36e62017c9c1f2229e2748b6dfbdb39a (patch)
tree218845ef248e9ba2131abd22404e3de9dfbf3cbd /src
parent759e6a24ab9690541acc6ece1adebaf524d6e5ae (diff)
downloademacs-88afd96e36e62017c9c1f2229e2748b6dfbdb39a.tar.gz
emacs-88afd96e36e62017c9c1f2229e2748b6dfbdb39a.zip
Fix build and running on Android 2.2
* INSTALL.android: Document that Android 2.2 is now supported, with caveats. * configure.ac (ANDROID_MIN_SDK, ANDROID_SDK_18_OR_EARLIER) (SYSTEM_TYPE, ANDROID_STUBIFY, SIZEOF_LONG): Correctly detect things missing on Android 2.2. * java/Makefile.in (ANDROID_JAR, JARSIGNER_FLAGS): * java/debug.sh (jdb, gdbserver, line): * java/org/gnu/emacs/EmacsApplication.java (findDumpFile): * java/org/gnu/emacs/EmacsService.java (onCreate): * java/org/gnu/emacs/EmacsThread.java (EmacsThread, run): Run parameter initialization on main thread. * src/android-asset.h (struct android_asset_manager) (struct android_asset, AAssetManager_fromJava, AAssetManager_open) (AAsset_close, android_asset_create_stream) (android_asset_read_internal, AAsset_openFileDescriptor) (AAsset_getLength, AAsset_getBuffer, AAsset_read): New file. * src/android.c (android_user_full_name, android_hack_asset_fd) (android_check_compressed_file): Implement for Android 2.2. * src/process.c (Fprocess_send_eof): Don't call tcdrain if unavailable. * src/sfntfont-android.c (system_font_directories): Fix compiler warning. * src/sfntfont.c (sfntfont_read_cmap): Correctly test rc of emacs_open. * src/textconv.c (handle_pending_conversion_events_1): Mark buffer UNINIT.
Diffstat (limited to 'src')
-rw-r--r--src/android-asset.h423
-rw-r--r--src/android.c72
-rw-r--r--src/process.c2
-rw-r--r--src/sfntfont-android.c2
-rw-r--r--src/sfntfont.c2
-rw-r--r--src/textconv.c2
6 files changed, 498 insertions, 5 deletions
diff --git a/src/android-asset.h b/src/android-asset.h
new file mode 100644
index 00000000000..b0e83bbf424
--- /dev/null
+++ b/src/android-asset.h
@@ -0,0 +1,423 @@
1/* Android initialization for GNU Emacs.
2
3Copyright (C) 2023 Free Software Foundation, Inc.
4
5This file is part of GNU Emacs.
6
7GNU Emacs is free software: you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation, either version 3 of the License, or (at
10your option) any later version.
11
12GNU Emacs is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
19
20#include <android/log.h>
21
22/* This file contains an emulation of the Android asset manager API
23 used on builds for Android 2.2. It is included by android.c
24 whenever appropriate.
25
26 The replacements in this file are not thread safe and must only be
27 called from the creating thread. */
28
29struct android_asset_manager
30{
31 /* JNI environment. */
32 JNIEnv *env;
33
34 /* Asset manager class and functions. */
35 jclass class;
36 jmethodID open_fd;
37
38 /* Asset file descriptor class and functions. */
39 jclass fd_class;
40 jmethodID get_length;
41 jmethodID create_input_stream;
42 jmethodID close;
43
44 /* Input stream class and functions. */
45 jclass input_stream_class;
46 jmethodID read;
47 jmethodID stream_close;
48
49 /* Associated asset manager object. */
50 jobject asset_manager;
51};
52
53typedef struct android_asset_manager AAssetManager;
54
55struct android_asset
56{
57 /* The asset manager. */
58 AAssetManager *manager;
59
60 /* The length of the asset, or -1. */
61 jlong length;
62
63 /* The asset file descriptor and input stream. */
64 jobject fd, stream;
65
66 /* The mode. */
67 int mode;
68};
69
70typedef struct android_asset AAsset;
71
72static AAssetManager *
73AAssetManager_fromJava (JNIEnv *env, jobject java_manager)
74{
75 AAssetManager *manager;
76 jclass temp;
77
78 manager = malloc (sizeof *manager);
79
80 if (!manager)
81 return NULL;
82
83 manager->env = env;
84 manager->asset_manager
85 = (*env)->NewGlobalRef (env, java_manager);
86
87 if (!manager->asset_manager)
88 {
89 free (manager);
90 return NULL;
91 }
92
93 manager->class
94 = (*env)->FindClass (env, "android/content/res/AssetManager");
95 assert (manager->class);
96
97 manager->open_fd
98 = (*env)->GetMethodID (env, manager->class, "openFd",
99 "(Ljava/lang/String;)"
100 "Landroid/content/res/AssetFileDescriptor;");
101 assert (manager->open);
102
103 manager->fd_class
104 = (*env)->FindClass (env, "android/content/res/AssetFileDescriptor");
105 assert (manager->fd_class);
106
107 manager->get_length
108 = (*env)->GetMethodID (env, manager->fd_class, "getLength",
109 "()J");
110 assert (manager->get_length);
111
112 manager->create_input_stream
113 = (*env)->GetMethodID (env, manager->fd_class,
114 "createInputStream",
115 "()Ljava/io/FileInputStream;");
116 assert (manager->create_input_stream);
117
118 manager->close
119 = (*env)->GetMethodID (env, manager->fd_class,
120 "close", "()V");
121 assert (manager->close);
122
123 manager->input_stream_class
124 = (*env)->FindClass (env, "java/io/InputStream");
125 assert (manager->input_stream_class);
126
127 manager->read
128 = (*env)->GetMethodID (env, manager->input_stream_class,
129 "read", "([B)I");
130 assert (manager->read);
131
132 manager->stream_close
133 = (*env)->GetMethodID (env, manager->input_stream_class,
134 "close", "()V");
135 assert (manager->stream_close);
136
137 /* Now convert all the class references to global ones. */
138 temp = manager->class;
139 manager->class
140 = (*env)->NewGlobalRef (env, temp);
141 assert (manager->class);
142 (*env)->DeleteLocalRef (env, temp);
143 temp = manager->fd_class;
144 manager->fd_class
145 = (*env)->NewGlobalRef (env, temp);
146 assert (manager->fd_class);
147 (*env)->DeleteLocalRef (env, temp);
148 temp = manager->input_stream_class;
149 manager->input_stream_class
150 = (*env)->NewGlobalRef (env, temp);
151 assert (manager->input_stream_class);
152 (*env)->DeleteLocalRef (env, temp);
153
154 /* Return the asset manager. */
155 return manager;
156}
157
158enum
159 {
160 AASSET_MODE_STREAMING = 0,
161 AASSET_MODE_BUFFER = 1,
162 };
163
164static AAsset *
165AAssetManager_open (AAssetManager *manager, const char *c_name,
166 int mode)
167{
168 jobject desc;
169 jstring name;
170 AAsset *asset;
171
172 /* Push a local frame. */
173 asset = NULL;
174
175 (*(manager->env))->PushLocalFrame (manager->env, 3);
176
177 if ((*(manager->env))->ExceptionCheck (manager->env))
178 goto fail;
179
180 /* Encoding issues can be ignored for now as there are only ASCII
181 file names in Emacs. */
182 name = (*(manager->env))->NewStringUTF (manager->env, c_name);
183
184 if (!name)
185 goto fail;
186
187 /* Now try to open an ``AssetFileDescriptor''. */
188 desc = (*(manager->env))->CallObjectMethod (manager->env,
189 manager->asset_manager,
190 manager->open_fd,
191 name);
192
193 if (!desc)
194 goto fail;
195
196 /* Allocate the asset. */
197 asset = calloc (1, sizeof *asset);
198
199 if (!asset)
200 {
201 (*(manager->env))->CallVoidMethod (manager->env,
202 desc,
203 manager->close);
204 goto fail;
205 }
206
207 /* Pop the local frame and return desc. */
208 desc = (*(manager->env))->NewGlobalRef (manager->env, desc);
209
210 if (!desc)
211 goto fail;
212
213 (*(manager->env))->PopLocalFrame (manager->env, NULL);
214
215 asset->manager = manager;
216 asset->length = -1;
217 asset->fd = desc;
218 asset->mode = mode;
219
220 return asset;
221
222 fail:
223 (*(manager->env))->ExceptionClear (manager->env);
224 (*(manager->env))->PopLocalFrame (manager->env, NULL);
225 free (asset);
226
227 return NULL;
228}
229
230static AAsset *
231AAsset_close (AAsset *asset)
232{
233 JNIEnv *env;
234
235 env = asset->manager->env;
236
237 (*env)->CallVoidMethod (asset->manager->env,
238 asset->fd,
239 asset->manager->close);
240 (*env)->DeleteGlobalRef (asset->manager->env,
241 asset->fd);
242
243 if (asset->stream)
244 {
245 (*env)->CallVoidMethod (asset->manager->env,
246 asset->stream,
247 asset->manager->stream_close);
248 (*env)->DeleteGlobalRef (asset->manager->env,
249 asset->stream);
250 }
251
252 free (asset);
253}
254
255/* Create an input stream associated with the given ASSET. Set
256 ASSET->stream to its global reference.
257
258 Value is 1 upon failure, else 0. ASSET must not already have an
259 input stream. */
260
261static int
262android_asset_create_stream (AAsset *asset)
263{
264 jobject stream;
265 JNIEnv *env;
266
267 env = asset->manager->env;
268 stream
269 = (*env)->CallObjectMethod (env, asset->fd,
270 asset->manager->create_input_stream);
271
272 if (!stream)
273 {
274 (*env)->ExceptionClear (env);
275 return 1;
276 }
277
278 asset->stream
279 = (*env)->NewGlobalRef (env, stream);
280
281 if (!asset->stream)
282 {
283 (*env)->ExceptionClear (env);
284 (*env)->DeleteLocalRef (env, stream);
285 return 1;
286 }
287
288 (*env)->DeleteLocalRef (env, stream);
289 return 0;
290}
291
292/* Read NBYTES from the specified asset into the given BUFFER;
293
294 Internally, allocate a Java byte array containing 4096 elements and
295 copy the data to and from that array.
296
297 Value is the number of bytes actually read, 0 at EOF, or -1 upon
298 failure, in which case errno is set accordingly. If NBYTES is
299 zero, behavior is undefined. */
300
301static int
302android_asset_read_internal (AAsset *asset, int nbytes, char *buffer)
303{
304 jbyteArray stash;
305 JNIEnv *env;
306 jint bytes_read, total;
307
308 /* Allocate a suitable amount of storage. Either nbytes or 4096,
309 whichever is larger. */
310 env = asset->manager->env;
311 stash = (*env)->NewByteArray (env, MIN (nbytes, 4096));
312
313 if (!stash)
314 {
315 (*env)->ExceptionClear (env);
316 errno = ENOMEM;
317 return -1;
318 }
319
320 /* Try to create an input stream. */
321
322 if (!asset->stream
323 && android_asset_create_stream (asset))
324 {
325 (*env)->DeleteLocalRef (env, stash);
326 errno = ENOMEM;
327 return -1;
328 }
329
330 /* Start reading. */
331
332 total = 0;
333
334 while (nbytes)
335 {
336 bytes_read = (*env)->CallIntMethod (env, asset->stream,
337 asset->manager->read,
338 stash);
339
340 /* Detect error conditions. */
341
342 if ((*env)->ExceptionCheck (env))
343 goto out;
344
345 /* Detect EOF. */
346
347 if (bytes_read == -1)
348 goto out;
349
350 /* Finally write out the amount that was read. */
351 bytes_read = MIN (bytes_read, nbytes);
352 (*env)->GetByteArrayRegion (env, stash, 0, bytes_read, buffer);
353
354 buffer += bytes_read;
355 total += bytes_read;
356 nbytes -= bytes_read;
357 }
358
359 /* Make sure the value of nbytes still makes sense. */
360 assert (nbytes >= 0);
361
362 out:
363 (*env)->ExceptionClear (env);
364 (*env)->DeleteLocalRef (env, stash);
365 return total;
366}
367
368static int
369AAsset_openFileDescriptor (AAsset *asset, off_t *out_start,
370 off_t *out_end)
371{
372 *out_start = 0;
373 *out_end = 0;
374 return -1;
375}
376
377static long
378AAsset_getLength (AAsset *asset)
379{
380 JNIEnv *env;
381
382 if (asset->length != -1)
383 return asset->length;
384
385 env = asset->manager->env;
386 asset->length
387 = (*env)->CallLongMethod (env, asset->fd,
388 asset->manager->get_length);
389 return asset->length;
390}
391
392static char *
393AAsset_getBuffer (AAsset *asset)
394{
395 long length;
396 char *buffer;
397
398 length = AAsset_getLength (asset);
399
400 if (!length)
401 return NULL;
402
403 buffer = malloc (length);
404
405 if (!buffer)
406 return NULL;
407
408 if (android_asset_read_internal (asset, length, buffer)
409 != length)
410 {
411 xfree (buffer);
412 return NULL;
413 }
414
415 return buffer;
416}
417
418static size_t
419AAsset_read (AAsset *asset, void *buffer, size_t size)
420{
421 return android_asset_read_internal (asset, MIN (size, INT_MAX),
422 buffer);
423}
diff --git a/src/android.c b/src/android.c
index 8f446224dab..09b9001b45d 100644
--- a/src/android.c
+++ b/src/android.c
@@ -32,6 +32,9 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
32#include <sys/mman.h> 32#include <sys/mman.h>
33#include <sys/param.h> 33#include <sys/param.h>
34 34
35/* Old NDK versions lack MIN and MAX. */
36#include <minmax.h>
37
35#include <assert.h> 38#include <assert.h>
36#include <fingerprint.h> 39#include <fingerprint.h>
37 40
@@ -49,8 +52,13 @@ bool android_init_gui;
49 52
50#ifndef ANDROID_STUBIFY 53#ifndef ANDROID_STUBIFY
51 54
55#if __ANDROID_API__ >= 9
52#include <android/asset_manager.h> 56#include <android/asset_manager.h>
53#include <android/asset_manager_jni.h> 57#include <android/asset_manager_jni.h>
58#else
59#include "android-asset.h"
60#endif
61
54#include <android/bitmap.h> 62#include <android/bitmap.h>
55#include <android/log.h> 63#include <android/log.h>
56 64
@@ -907,10 +915,14 @@ android_is_directory (const char *dir)
907char * 915char *
908android_user_full_name (struct passwd *pw) 916android_user_full_name (struct passwd *pw)
909{ 917{
918#ifdef HAVE_STRUCT_PASSWD_PW_GECOS
910 if (!pw->pw_gecos) 919 if (!pw->pw_gecos)
911 return (char *) "Android user"; 920 return (char *) "Android user";
912 921
913 return pw->pw_gecos; 922 return pw->pw_gecos;
923#else
924 return "Android user";
925#endif
914} 926}
915 927
916/* Given a real file name, return the part that describes its asset 928/* Given a real file name, return the part that describes its asset
@@ -1048,6 +1060,60 @@ android_file_access_p (const char *name, int amode)
1048static int 1060static int
1049android_hack_asset_fd (AAsset *asset) 1061android_hack_asset_fd (AAsset *asset)
1050{ 1062{
1063#if __ANDROID_API__ < 9
1064 int fd;
1065 char filename[PATH_MAX];
1066 size_t size;
1067 void *mem;
1068
1069 /* Assets must be small enough to fit in size_t, if off_t is
1070 larger. */
1071 size = AAsset_getLength (asset);
1072
1073 /* Get an unlinked file descriptor from a file in the cache
1074 directory, which is guaranteed to only be written to by Emacs.
1075 Creating an asset file descriptor doesn't work on these old
1076 Android versions. */
1077
1078 snprintf (filename, PATH_MAX, "%s/%s.%d",
1079 android_cache_dir, "temp-unlinked",
1080 getpid ());
1081 fd = open (filename, O_CREAT | O_RDWR | O_TRUNC,
1082 S_IRUSR | S_IWUSR);
1083
1084 if (fd < 1)
1085 return -1;
1086
1087 if (unlink (filename))
1088 goto fail;
1089
1090 if (ftruncate (fd, size))
1091 goto fail;
1092
1093 mem = mmap (NULL, size, PROT_WRITE, MAP_SHARED, fd, 0);
1094 if (mem == MAP_FAILED)
1095 {
1096 __android_log_print (ANDROID_LOG_ERROR, __func__,
1097 "mmap: %s", strerror (errno));
1098 goto fail;
1099 }
1100
1101 if (AAsset_read (asset, mem, size) != size)
1102 {
1103 /* Too little was read. Close the file descriptor and
1104 report an error. */
1105 __android_log_print (ANDROID_LOG_ERROR, __func__,
1106 "AAsset_read: %s", strerror (errno));
1107 goto fail;
1108 }
1109
1110 munmap (mem, size);
1111 return fd;
1112
1113 fail:
1114 close (fd);
1115 return -1;
1116#else
1051 int fd, rc; 1117 int fd, rc;
1052 unsigned char *mem; 1118 unsigned char *mem;
1053 size_t size; 1119 size_t size;
@@ -1172,10 +1238,11 @@ android_hack_asset_fd (AAsset *asset)
1172 /* Return anyway even if munmap fails. */ 1238 /* Return anyway even if munmap fails. */
1173 munmap (mem, size); 1239 munmap (mem, size);
1174 return fd; 1240 return fd;
1241#endif
1175} 1242}
1176 1243
1177/* Read two bytes from FD and see if they are ``PK'', denoting ZIP 1244/* Read two bytes from FD and see if they are ``PK'', denoting ZIP
1178 archive compressed data. 1245 archive compressed data. If FD is -1, return -1.
1179 1246
1180 If they are not, rewind the file descriptor to offset 0. 1247 If they are not, rewind the file descriptor to offset 0.
1181 1248
@@ -1187,6 +1254,9 @@ android_check_compressed_file (int fd)
1187{ 1254{
1188 char bytes[2]; 1255 char bytes[2];
1189 1256
1257 if (fd == -1)
1258 return -1;
1259
1190 if (read (fd, bytes, 2) != 2) 1260 if (read (fd, bytes, 2) != 2)
1191 goto lseek_back; 1261 goto lseek_back;
1192 1262
diff --git a/src/process.c b/src/process.c
index e7ccb2c604e..bdaaba70fea 100644
--- a/src/process.c
+++ b/src/process.c
@@ -7248,7 +7248,7 @@ process has been transmitted to the serial port. */)
7248 send_process (proc, "\004", 1, Qnil); 7248 send_process (proc, "\004", 1, Qnil);
7249 else if (EQ (XPROCESS (proc)->type, Qserial)) 7249 else if (EQ (XPROCESS (proc)->type, Qserial))
7250 { 7250 {
7251#ifndef WINDOWSNT 7251#if !defined WINDOWSNT && defined HAVE_TCDRAIN
7252 if (tcdrain (XPROCESS (proc)->outfd) != 0) 7252 if (tcdrain (XPROCESS (proc)->outfd) != 0)
7253 report_file_error ("Failed tcdrain", Qnil); 7253 report_file_error ("Failed tcdrain", Qnil);
7254#endif /* not WINDOWSNT */ 7254#endif /* not WINDOWSNT */
diff --git a/src/sfntfont-android.c b/src/sfntfont-android.c
index c28a911bfba..8324185cc6f 100644
--- a/src/sfntfont-android.c
+++ b/src/sfntfont-android.c
@@ -51,7 +51,7 @@ struct sfntfont_android_scanline_buffer
51/* Array of directories to search for system fonts. */ 51/* Array of directories to search for system fonts. */
52static char *system_font_directories[] = 52static char *system_font_directories[] =
53 { 53 {
54 "/system/fonts", 54 (char *) "/system/fonts",
55 /* This should be filled in by init_sfntfont_android. */ 55 /* This should be filled in by init_sfntfont_android. */
56 (char[PATH_MAX]) { }, 56 (char[PATH_MAX]) { },
57 }; 57 };
diff --git a/src/sfntfont.c b/src/sfntfont.c
index f9344067f1a..20c109f2401 100644
--- a/src/sfntfont.c
+++ b/src/sfntfont.c
@@ -953,7 +953,7 @@ sfntfont_read_cmap (struct sfnt_font_desc *desc,
953 /* Pick a character map and place it in *CMAP. */ 953 /* Pick a character map and place it in *CMAP. */
954 fd = emacs_open (desc->path, O_RDONLY, 0); 954 fd = emacs_open (desc->path, O_RDONLY, 0);
955 955
956 if (fd < 1) 956 if (fd < 0)
957 return; 957 return;
958 958
959 font = sfnt_read_table_directory (fd); 959 font = sfnt_read_table_directory (fd);
diff --git a/src/textconv.c b/src/textconv.c
index 5090b0a33b6..8f5a4987d5a 100644
--- a/src/textconv.c
+++ b/src/textconv.c
@@ -989,7 +989,7 @@ handle_pending_conversion_events_1 (struct frame *f,
989{ 989{
990 Lisp_Object data; 990 Lisp_Object data;
991 enum text_conversion_operation operation; 991 enum text_conversion_operation operation;
992 struct buffer *buffer; 992 struct buffer *buffer UNINIT;
993 struct window *w; 993 struct window *w;
994 specpdl_ref count; 994 specpdl_ref count;
995 unsigned long token; 995 unsigned long token;