aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPo Lu2023-02-25 20:11:48 +0800
committerPo Lu2023-02-25 20:11:48 +0800
commitdf29bb71fc47b5e24fa971b668e4fa09dd6d244d (patch)
tree78672c8e9f3b3db96f59a2bf6f81107d9eadb4af
parent8e4c5db193dc7baee5846520fe8b63d8bea99148 (diff)
downloademacs-df29bb71fc47b5e24fa971b668e4fa09dd6d244d.tar.gz
emacs-df29bb71fc47b5e24fa971b668e4fa09dd6d244d.zip
Update Android port
* java/org/gnu/emacs/EmacsNoninteractive.java (main): Port to Android 2.2. * src/android-asset.h (AAsset_openFileDescriptor): Delete stub function. * src/android.c (android_check_compressed_file): Delete function. (android_open): Stop trying to find compressed files or to use the system provided file descriptor. Explain why.
-rw-r--r--java/org/gnu/emacs/EmacsNoninteractive.java118
-rw-r--r--src/android-asset.h9
-rw-r--r--src/android.c65
3 files changed, 87 insertions, 105 deletions
diff --git a/java/org/gnu/emacs/EmacsNoninteractive.java b/java/org/gnu/emacs/EmacsNoninteractive.java
index 4da82f2f894..30901edb75f 100644
--- a/java/org/gnu/emacs/EmacsNoninteractive.java
+++ b/java/org/gnu/emacs/EmacsNoninteractive.java
@@ -87,56 +87,23 @@ public class EmacsNoninteractive
87 87
88 /* Create and attach the activity thread. */ 88 /* Create and attach the activity thread. */
89 activityThread = method.invoke (null); 89 activityThread = method.invoke (null);
90 context = null;
90 91
91 /* Now get an LoadedApk. */ 92 /* Now get an LoadedApk. */
92 loadedApkClass = Class.forName ("android.app.LoadedApk");
93 93
94 /* Get a LoadedApk. How to do this varies by Android version. 94 try
95 On Android 2.3.3 and earlier, there is no
96 ``compatibilityInfo'' argument to getPackageInfo. */
97
98 if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.GINGERBREAD_MR1)
99 { 95 {
100 method 96 loadedApkClass = Class.forName ("android.app.LoadedApk");
101 = activityThreadClass.getMethod ("getPackageInfo",
102 String.class,
103 int.class);
104 loadedApk = method.invoke (activityThread, "org.gnu.emacs",
105 0);
106 } 97 }
107 else 98 catch (ClassNotFoundException exception)
108 { 99 {
109 compatibilityInfoClass 100 /* Android 2.2 has no LoadedApk class, but fortunately it
110 = Class.forName ("android.content.res.CompatibilityInfo"); 101 does not need to be used, since contexts can be
111 102 directly created. */
112 method
113 = activityThreadClass.getMethod ("getPackageInfo",
114 String.class,
115 compatibilityInfoClass,
116 int.class);
117 loadedApk = method.invoke (activityThread, "org.gnu.emacs", null,
118 0);
119 }
120
121 if (loadedApk == null)
122 throw new RuntimeException ("getPackageInfo returned NULL");
123 103
124 /* Now, get a context. */ 104 loadedApkClass = null;
125 contextImplClass = Class.forName ("android.app.ContextImpl"); 105 contextImplClass = Class.forName ("android.app.ContextImpl");
126 106
127 try
128 {
129 method = contextImplClass.getDeclaredMethod ("createAppContext",
130 activityThreadClass,
131 loadedApkClass);
132 method.setAccessible (true);
133 context = (Context) method.invoke (null, activityThread, loadedApk);
134 }
135 catch (NoSuchMethodException exception)
136 {
137 /* Older Android versions don't have createAppContext, but
138 instead require creating a ContextImpl, and then
139 calling createPackageContext. */
140 method = activityThreadClass.getDeclaredMethod ("getSystemContext"); 107 method = activityThreadClass.getDeclaredMethod ("getSystemContext");
141 context = (Context) method.invoke (activityThread); 108 context = (Context) method.invoke (activityThread);
142 method = contextImplClass.getDeclaredMethod ("createPackageContext", 109 method = contextImplClass.getDeclaredMethod ("createPackageContext",
@@ -147,6 +114,73 @@ public class EmacsNoninteractive
147 0); 114 0);
148 } 115 }
149 116
117 /* If the context has not already been created, then do what
118 is appropriate for newer versions of Android. */
119
120 if (context == null)
121 {
122 /* Get a LoadedApk. How to do this varies by Android version.
123 On Android 2.3.3 and earlier, there is no
124 ``compatibilityInfo'' argument to getPackageInfo. */
125
126 if (Build.VERSION.SDK_INT
127 <= Build.VERSION_CODES.GINGERBREAD_MR1)
128 {
129 method
130 = activityThreadClass.getMethod ("getPackageInfo",
131 String.class,
132 int.class);
133 loadedApk = method.invoke (activityThread, "org.gnu.emacs",
134 0);
135 }
136 else
137 {
138 compatibilityInfoClass
139 = Class.forName ("android.content.res.CompatibilityInfo");
140
141 method
142 = activityThreadClass.getMethod ("getPackageInfo",
143 String.class,
144 compatibilityInfoClass,
145 int.class);
146 loadedApk = method.invoke (activityThread, "org.gnu.emacs",
147 null, 0);
148 }
149
150 if (loadedApk == null)
151 throw new RuntimeException ("getPackageInfo returned NULL");
152
153 /* Now, get a context. */
154 contextImplClass = Class.forName ("android.app.ContextImpl");
155
156 try
157 {
158 method
159 = contextImplClass.getDeclaredMethod ("createAppContext",
160 activityThreadClass,
161 loadedApkClass);
162 method.setAccessible (true);
163 context = (Context) method.invoke (null, activityThread,
164 loadedApk);
165 }
166 catch (NoSuchMethodException exception)
167 {
168 /* Older Android versions don't have createAppContext, but
169 instead require creating a ContextImpl, and then
170 calling createPackageContext. */
171 method
172 = activityThreadClass.getDeclaredMethod ("getSystemContext");
173 context = (Context) method.invoke (activityThread);
174 method
175 = contextImplClass.getDeclaredMethod ("createPackageContext",
176 String.class,
177 int.class);
178 method.setAccessible (true);
179 context = (Context) method.invoke (context, "org.gnu.emacs",
180 0);
181 }
182 }
183
150 /* Don't actually start the looper or anything. Instead, obtain 184 /* Don't actually start the looper or anything. Instead, obtain
151 an AssetManager. */ 185 an AssetManager. */
152 assets = context.getAssets (); 186 assets = context.getAssets ();
diff --git a/src/android-asset.h b/src/android-asset.h
index b0e83bbf424..3b2f8105865 100644
--- a/src/android-asset.h
+++ b/src/android-asset.h
@@ -365,15 +365,6 @@ android_asset_read_internal (AAsset *asset, int nbytes, char *buffer)
365 return total; 365 return total;
366} 366}
367 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 368static long
378AAsset_getLength (AAsset *asset) 369AAsset_getLength (AAsset *asset)
379{ 370{
diff --git a/src/android.c b/src/android.c
index 72c50c0a13c..40d6234d508 100644
--- a/src/android.c
+++ b/src/android.c
@@ -1376,42 +1376,6 @@ android_hack_asset_fd (AAsset *asset)
1376#endif 1376#endif
1377} 1377}
1378 1378
1379/* Read two bytes from FD and see if they are ``PK'', denoting ZIP
1380 archive compressed data. If FD is -1, return -1.
1381
1382 If they are not, rewind the file descriptor to offset 0.
1383
1384 If either operation fails, return -1 and close FD. Else, value is
1385 FD. */
1386
1387static int
1388android_check_compressed_file (int fd)
1389{
1390 char bytes[2];
1391
1392 if (fd == -1)
1393 return -1;
1394
1395 if (read (fd, bytes, 2) != 2)
1396 goto lseek_back;
1397
1398 if (bytes[0] != 'P' || bytes[1] != 'K')
1399 goto lseek_back;
1400
1401 /* This could be compressed data! */
1402 return -1;
1403
1404 lseek_back:
1405 /* Seek back to offset 0. If this fails, return -1. */
1406 if (lseek (fd, 0, SEEK_SET) != 0)
1407 {
1408 close (fd);
1409 return -1;
1410 }
1411
1412 return fd;
1413}
1414
1415/* Make FD close-on-exec. If any system call fails, do not abort, but 1379/* Make FD close-on-exec. If any system call fails, do not abort, but
1416 log a warning to the system log. */ 1380 log a warning to the system log. */
1417 1381
@@ -1482,28 +1446,21 @@ android_open (const char *filename, int oflag, int mode)
1482 return -1; 1446 return -1;
1483 } 1447 }
1484 1448
1485 /* Try to obtain the file descriptor corresponding to this 1449 /* Create a shared memory file descriptor containing the asset
1486 asset. */ 1450 contents.
1487 fd = AAsset_openFileDescriptor (asset, &out_start, 1451
1488 &out_length); 1452 The documentation misleads people into thinking that
1453 AAsset_openFileDescriptor does precisely this. However, it
1454 instead returns an offset into any uncompressed assets in the
1455 ZIP archive. This cannot be found in its documentation. */
1489 1456
1490 /* The platform sometimes returns a file descriptor to ZIP 1457 fd = android_hack_asset_fd (asset);
1491 compressed data. Detect that and fall back to creating a
1492 shared memory file descriptor. */
1493 fd = android_check_compressed_file (fd);
1494 1458
1495 if (fd == -1) 1459 if (fd == -1)
1496 { 1460 {
1497 /* The asset can't be accessed for some reason. Try to 1461 AAsset_close (asset);
1498 create a shared memory file descriptor. */ 1462 errno = ENXIO;
1499 fd = android_hack_asset_fd (asset); 1463 return -1;
1500
1501 if (fd == -1)
1502 {
1503 AAsset_close (asset);
1504 errno = ENXIO;
1505 return -1;
1506 }
1507 } 1464 }
1508 1465
1509 /* If O_CLOEXEC is specified, make the file descriptor close on 1466 /* If O_CLOEXEC is specified, make the file descriptor close on