aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorPo Lu2023-02-26 10:33:41 +0800
committerPo Lu2023-02-26 10:33:41 +0800
commit39ddf1855bbebc5d31b544e6308a4ae49f4925b3 (patch)
tree874c9903ca54abd0abcaed2c98d03a1d3fec9633 /src
parent687f4fadde4fda8a320cbb4e26518af1034cbb9a (diff)
downloademacs-39ddf1855bbebc5d31b544e6308a4ae49f4925b3.tar.gz
emacs-39ddf1855bbebc5d31b544e6308a4ae49f4925b3.zip
Update Android port
* doc/lispref/commands.texi (Misc Events): Update documentation. * java/org/gnu/emacs/EmacsService.java (EmacsService) (onStartCommand): Improve notification message. * src/android.c (android_hack_asset_fd): Detect if ashmem is available dynamically. (android_detect_ashmem): New function. * src/textconv.c (record_buffer_change): Use markers to represent BEG and END instead. (syms_of_textconv): Update doc string.
Diffstat (limited to 'src')
-rw-r--r--src/android.c152
-rw-r--r--src/textconv.c38
2 files changed, 172 insertions, 18 deletions
diff --git a/src/android.c b/src/android.c
index 99c612f13df..cf6ddd736eb 100644
--- a/src/android.c
+++ b/src/android.c
@@ -1202,13 +1202,13 @@ android_file_access_p (const char *name, int amode)
1202 return false; 1202 return false;
1203} 1203}
1204 1204
1205/* Get a file descriptor backed by a temporary in-memory file for the 1205/* Do the same as android_hack_asset_fd, but use an unlinked temporary
1206 given asset. */ 1206 file to cater to old Android kernels where ashmem files are not
1207 readable. */
1207 1208
1208static int 1209static int
1209android_hack_asset_fd (AAsset *asset) 1210android_hack_asset_fd_fallback (AAsset *asset)
1210{ 1211{
1211#if __ANDROID_API__ < 9
1212 int fd; 1212 int fd;
1213 char filename[PATH_MAX]; 1213 char filename[PATH_MAX];
1214 size_t size; 1214 size_t size;
@@ -1220,8 +1220,8 @@ android_hack_asset_fd (AAsset *asset)
1220 1220
1221 /* Get an unlinked file descriptor from a file in the cache 1221 /* Get an unlinked file descriptor from a file in the cache
1222 directory, which is guaranteed to only be written to by Emacs. 1222 directory, which is guaranteed to only be written to by Emacs.
1223 Creating an asset file descriptor doesn't work on these old 1223 Creating an ashmem file descriptor and reading from it doesn't
1224 Android versions. */ 1224 work on these old Android versions. */
1225 1225
1226 snprintf (filename, PATH_MAX, "%s/%s.%d", 1226 snprintf (filename, PATH_MAX, "%s/%s.%d",
1227 android_cache_dir, "temp-unlinked", 1227 android_cache_dir, "temp-unlinked",
@@ -1261,11 +1261,146 @@ android_hack_asset_fd (AAsset *asset)
1261 fail: 1261 fail:
1262 close (fd); 1262 close (fd);
1263 return -1; 1263 return -1;
1264#else 1264}
1265
1266/* Pointer to the `ASharedMemory_create' function which is loaded
1267 dynamically. */
1268static int (*asharedmemory_create) (const char *, size_t);
1269
1270/* Return whether or not shared memory file descriptors can also be
1271 read from, and are thus suitable for creating asset files.
1272
1273 This does not work on some ancient Android systems running old
1274 versions of the kernel. */
1275
1276static bool
1277android_detect_ashmem (void)
1278{
1279 int fd, rc;
1280 void *mem;
1281 char test_buffer[10];
1282
1283 memcpy (test_buffer, "abcdefghi", 10);
1284
1285 /* Create the file descriptor to be used for the test. */
1286
1287 /* Android 28 and earlier let Emacs access /dev/ashmem directly, so
1288 prefer that over using ASharedMemory. */
1289
1290 if (android_api_level <= 28)
1291 {
1292 fd = open ("/dev/ashmem", O_RDWR);
1293
1294 if (fd < 0)
1295 return false;
1296
1297 /* An empty name means the memory area will exist until the file
1298 descriptor is closed, because no other process can
1299 attach. */
1300 rc = ioctl (fd, ASHMEM_SET_NAME, "");
1301
1302 if (rc < 0)
1303 {
1304 close (fd);
1305 return false;
1306 }
1307
1308 rc = ioctl (fd, ASHMEM_SET_SIZE, sizeof test_buffer);
1309
1310 if (rc < 0)
1311 {
1312 close (fd);
1313 return false;
1314 }
1315 }
1316 else
1317 {
1318 /* On the other hand, SELinux restrictions on Android 29 and
1319 later require that Emacs use a system service to obtain
1320 shared memory. Load this dynamically, as this service is not
1321 available on all versions of the NDK. */
1322
1323 if (!asharedmemory_create)
1324 {
1325 *(void **) (&asharedmemory_create)
1326 = dlsym (RTLD_DEFAULT, "ASharedMemory_create");
1327
1328 if (!asharedmemory_create)
1329 {
1330 __android_log_print (ANDROID_LOG_FATAL, __func__,
1331 "dlsym: %s\n",
1332 strerror (errno));
1333 emacs_abort ();
1334 }
1335 }
1336
1337 fd = asharedmemory_create ("", sizeof test_buffer);
1338
1339 if (fd < 0)
1340 return false;
1341 }
1342
1343 /* Now map the resource and write the test contents. */
1344
1345 mem = mmap (NULL, sizeof test_buffer, PROT_WRITE,
1346 MAP_SHARED, fd, 0);
1347 if (mem == MAP_FAILED)
1348 {
1349 close (fd);
1350 return false;
1351 }
1352
1353 /* Copy over the test contents. */
1354 memcpy (mem, test_buffer, sizeof test_buffer);
1355
1356 /* Return anyway even if munmap fails. */
1357 munmap (mem, sizeof test_buffer);
1358
1359 /* Try to read the content back into test_buffer. If this does not
1360 compare equal to the original string, or the read fails, then
1361 ashmem descriptors are not readable on this system. */
1362
1363 if ((read (fd, test_buffer, sizeof test_buffer)
1364 != sizeof test_buffer)
1365 || memcmp (test_buffer, "abcdefghi", sizeof test_buffer))
1366 {
1367 __android_log_print (ANDROID_LOG_WARN, __func__,
1368 "/dev/ashmem does not produce real"
1369 " temporary files on this system, so"
1370 " Emacs will fall back to creating"
1371 " unlinked temporary files.");
1372 close (fd);
1373 return false;
1374 }
1375
1376 close (fd);
1377 return true;
1378}
1379
1380/* Get a file descriptor backed by a temporary in-memory file for the
1381 given asset. */
1382
1383static int
1384android_hack_asset_fd (AAsset *asset)
1385{
1386 static bool ashmem_readable_p;
1387 static bool ashmem_initialized;
1265 int fd, rc; 1388 int fd, rc;
1266 unsigned char *mem; 1389 unsigned char *mem;
1267 size_t size; 1390 size_t size;
1268 static int (*asharedmemory_create) (const char *, size_t); 1391
1392 /* The first time this function is called, try to determine whether
1393 or not ashmem file descriptors can be read from. */
1394
1395 if (!ashmem_initialized)
1396 ashmem_readable_p
1397 = android_detect_ashmem ();
1398 ashmem_initialized = true;
1399
1400 /* If it isn't, fall back. */
1401
1402 if (!ashmem_readable_p)
1403 return android_hack_asset_fd_fallback (asset);
1269 1404
1270 /* Assets must be small enough to fit in size_t, if off_t is 1405 /* Assets must be small enough to fit in size_t, if off_t is
1271 larger. */ 1406 larger. */
@@ -1386,7 +1521,6 @@ android_hack_asset_fd (AAsset *asset)
1386 /* Return anyway even if munmap fails. */ 1521 /* Return anyway even if munmap fails. */
1387 munmap (mem, size); 1522 munmap (mem, size);
1388 return fd; 1523 return fd;
1389#endif
1390} 1524}
1391 1525
1392/* Make FD close-on-exec. If any system call fails, do not abort, but 1526/* Make FD close-on-exec. If any system call fails, do not abort, but
diff --git a/src/textconv.c b/src/textconv.c
index 4b5f9e01162..3da8dc831c8 100644
--- a/src/textconv.c
+++ b/src/textconv.c
@@ -430,13 +430,32 @@ static void
430record_buffer_change (ptrdiff_t beg, ptrdiff_t end, 430record_buffer_change (ptrdiff_t beg, ptrdiff_t end,
431 Lisp_Object ephemeral) 431 Lisp_Object ephemeral)
432{ 432{
433 Lisp_Object buffer; 433 Lisp_Object buffer, beg_marker, end_marker;
434 434
435 XSETBUFFER (buffer, current_buffer); 435 XSETBUFFER (buffer, current_buffer);
436 436
437 /* Make markers for both BEG and END. */
438 beg_marker = build_marker (current_buffer, beg,
439 CHAR_TO_BYTE (beg));
440
441 /* If BEG and END are identical, make sure to keep the markers
442 eq. */
443
444 if (beg == end)
445 end_marker = beg_marker;
446 else
447 {
448 end_marker = build_marker (current_buffer, end,
449 CHAR_TO_BYTE (end));
450
451 /* Otherwise, make sure the marker extends past inserted
452 text. */
453 Fset_marker_insertion_type (end_marker, Qt);
454 }
455
437 Vtext_conversion_edits 456 Vtext_conversion_edits
438 = Fcons (list4 (buffer, make_fixnum (beg), 457 = Fcons (list4 (buffer, beg_marker, end_marker,
439 make_fixnum (end), ephemeral), 458 ephemeral),
440 Vtext_conversion_edits); 459 Vtext_conversion_edits);
441} 460}
442 461
@@ -1720,19 +1739,20 @@ form:
1720 1739
1721 (BUFFER BEG END EPHEMERAL) 1740 (BUFFER BEG END EPHEMERAL)
1722 1741
1723If an insertion or a change occured, then BEG and END are buffer 1742If an insertion or a change occured, then BEG and END are markers
1724positions denote the bounds of the text that was changed or inserted. 1743which denote the bounds of the text that was changed or inserted.
1744
1725If EPHEMERAL is t, then the input method will shortly make more 1745If EPHEMERAL is t, then the input method will shortly make more
1726changes to the text, so any actions that would otherwise be taken 1746changes to the text, so any actions that would otherwise be taken
1727(such as indenting or automatically filling text) should not take 1747(such as indenting or automatically filling text) should not take
1728place; otherwise, it is a string describing the text which was 1748place; otherwise, it is a string describing the text which was
1729inserted. 1749inserted.
1730 1750
1731If a deletion occured before point, then BEG and END are the same, and 1751If a deletion occured before point, then BEG and END are the same
1732EPHEMERAL is the text which was deleted. 1752object, and EPHEMERAL is the text which was deleted.
1733 1753
1734If a deletion occured after point, then BEG and END are also the same, 1754If a deletion occured after point, then BEG and END are also the same
1735but EPHEMERAL is nil. 1755object, but EPHEMERAL is nil.
1736 1756
1737The list contents are ordered later edits first, so you must iterate 1757The list contents are ordered later edits first, so you must iterate
1738through the list in reverse. */); 1758through the list in reverse. */);