]> git.eshelyaron.com Git - emacs.git/commitdiff
Update Android port
authorPo Lu <luangruo@yahoo.com>
Sat, 25 Feb 2023 12:11:48 +0000 (20:11 +0800)
committerPo Lu <luangruo@yahoo.com>
Sat, 25 Feb 2023 12:11:48 +0000 (20:11 +0800)
* 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.

java/org/gnu/emacs/EmacsNoninteractive.java
src/android-asset.h
src/android.c

index 4da82f2f894937c0edc0aca93c252fcc68fe0fc6..30901edb75fa7cf0dc2061b481eb302e262e1f42 100644 (file)
@@ -87,56 +87,23 @@ public class EmacsNoninteractive
 
        /* Create and attach the activity thread.  */
        activityThread = method.invoke (null);
+       context = null;
 
        /* Now get an LoadedApk.  */
-       loadedApkClass = Class.forName ("android.app.LoadedApk");
 
-       /* Get a LoadedApk.  How to do this varies by Android version.
-          On Android 2.3.3 and earlier, there is no
-          ``compatibilityInfo'' argument to getPackageInfo.  */
-
-       if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.GINGERBREAD_MR1)
+       try
          {
-           method
-             = activityThreadClass.getMethod ("getPackageInfo",
-                                              String.class,
-                                              int.class);
-           loadedApk = method.invoke (activityThread, "org.gnu.emacs",
-                                      0);
+           loadedApkClass = Class.forName ("android.app.LoadedApk");
          }
-       else
+       catch (ClassNotFoundException exception)
          {
-           compatibilityInfoClass
-             = Class.forName ("android.content.res.CompatibilityInfo");
-
-           method
-             = activityThreadClass.getMethod ("getPackageInfo",
-                                              String.class,
-                                              compatibilityInfoClass,
-                                              int.class);
-           loadedApk = method.invoke (activityThread, "org.gnu.emacs", null,
-                                      0);
-         }
-
-       if (loadedApk == null)
-         throw new RuntimeException ("getPackageInfo returned NULL");
+           /* Android 2.2 has no LoadedApk class, but fortunately it
+              does not need to be used, since contexts can be
+              directly created.  */
 
-       /* Now, get a context.  */
-       contextImplClass = Class.forName ("android.app.ContextImpl");
+           loadedApkClass = null;
+           contextImplClass = Class.forName ("android.app.ContextImpl");
 
-       try
-         {
-           method = contextImplClass.getDeclaredMethod ("createAppContext",
-                                                        activityThreadClass,
-                                                        loadedApkClass);
-           method.setAccessible (true);
-           context = (Context) method.invoke (null, activityThread, loadedApk);
-         }
-       catch (NoSuchMethodException exception)
-         {
-           /* Older Android versions don't have createAppContext, but
-              instead require creating a ContextImpl, and then
-              calling createPackageContext.  */
            method = activityThreadClass.getDeclaredMethod ("getSystemContext");
            context = (Context) method.invoke (activityThread);
            method = contextImplClass.getDeclaredMethod ("createPackageContext",
@@ -147,6 +114,73 @@ public class EmacsNoninteractive
                                               0);
          }
 
+       /* If the context has not already been created, then do what
+          is appropriate for newer versions of Android.  */
+
+       if (context == null)
+         {
+           /* Get a LoadedApk.  How to do this varies by Android version.
+              On Android 2.3.3 and earlier, there is no
+              ``compatibilityInfo'' argument to getPackageInfo.  */
+
+           if (Build.VERSION.SDK_INT
+               <= Build.VERSION_CODES.GINGERBREAD_MR1)
+             {
+               method
+                 = activityThreadClass.getMethod ("getPackageInfo",
+                                                  String.class,
+                                                  int.class);
+               loadedApk = method.invoke (activityThread, "org.gnu.emacs",
+                                          0);
+             }
+           else
+             {
+               compatibilityInfoClass
+                 = Class.forName ("android.content.res.CompatibilityInfo");
+
+               method
+                 = activityThreadClass.getMethod ("getPackageInfo",
+                                                  String.class,
+                                                  compatibilityInfoClass,
+                                                  int.class);
+               loadedApk = method.invoke (activityThread, "org.gnu.emacs",
+                                          null, 0);
+             }
+
+           if (loadedApk == null)
+             throw new RuntimeException ("getPackageInfo returned NULL");
+
+           /* Now, get a context.  */
+           contextImplClass = Class.forName ("android.app.ContextImpl");
+
+           try
+             {
+               method
+                 = contextImplClass.getDeclaredMethod ("createAppContext",
+                                                       activityThreadClass,
+                                                       loadedApkClass);
+               method.setAccessible (true);
+               context = (Context) method.invoke (null, activityThread,
+                                                  loadedApk);
+             }
+           catch (NoSuchMethodException exception)
+             {
+               /* Older Android versions don't have createAppContext, but
+                  instead require creating a ContextImpl, and then
+                  calling createPackageContext.  */
+               method
+                 = activityThreadClass.getDeclaredMethod ("getSystemContext");
+               context = (Context) method.invoke (activityThread);
+               method
+                 = contextImplClass.getDeclaredMethod ("createPackageContext",
+                                                       String.class,
+                                                       int.class);
+               method.setAccessible (true);
+               context = (Context) method.invoke (context, "org.gnu.emacs",
+                                                  0);
+             }
+         }
+
        /* Don't actually start the looper or anything.  Instead, obtain
           an AssetManager.  */
        assets = context.getAssets ();
index b0e83bbf4245c09739b46ea722adf845896be2f5..3b2f81058651c99268e2ed5a86ac6069d0dc0847 100644 (file)
@@ -365,15 +365,6 @@ android_asset_read_internal (AAsset *asset, int nbytes, char *buffer)
   return total;
 }
 
-static int
-AAsset_openFileDescriptor (AAsset *asset, off_t *out_start,
-                          off_t *out_end)
-{
-  *out_start = 0;
-  *out_end = 0;
-  return -1;
-}
-
 static long
 AAsset_getLength (AAsset *asset)
 {
index 72c50c0a13c9c5f48a729f8a8f05c24419892742..40d6234d508f6785949d59eada1a31bdac579f97 100644 (file)
@@ -1376,42 +1376,6 @@ android_hack_asset_fd (AAsset *asset)
 #endif
 }
 
-/* Read two bytes from FD and see if they are ``PK'', denoting ZIP
-   archive compressed data.  If FD is -1, return -1.
-
-   If they are not, rewind the file descriptor to offset 0.
-
-   If either operation fails, return -1 and close FD.  Else, value is
-   FD.  */
-
-static int
-android_check_compressed_file (int fd)
-{
-  char bytes[2];
-
-  if (fd == -1)
-    return -1;
-
-  if (read (fd, bytes, 2) != 2)
-    goto lseek_back;
-
-  if (bytes[0] != 'P' || bytes[1] != 'K')
-    goto lseek_back;
-
-  /* This could be compressed data! */
-  return -1;
-
- lseek_back:
-  /* Seek back to offset 0.  If this fails, return -1.  */
-  if (lseek (fd, 0, SEEK_SET) != 0)
-    {
-      close (fd);
-      return -1;
-    }
-
-  return fd;
-}
-
 /* Make FD close-on-exec.  If any system call fails, do not abort, but
    log a warning to the system log.  */
 
@@ -1482,28 +1446,21 @@ android_open (const char *filename, int oflag, int mode)
          return -1;
        }
 
-      /* Try to obtain the file descriptor corresponding to this
-        asset.  */
-      fd = AAsset_openFileDescriptor (asset, &out_start,
-                                     &out_length);
+      /* Create a shared memory file descriptor containing the asset
+        contents.
+
+         The documentation misleads people into thinking that
+         AAsset_openFileDescriptor does precisely this.  However, it
+         instead returns an offset into any uncompressed assets in the
+         ZIP archive.  This cannot be found in its documentation.  */
 
-      /* The platform sometimes returns a file descriptor to ZIP
-        compressed data.  Detect that and fall back to creating a
-        shared memory file descriptor.  */
-      fd = android_check_compressed_file (fd);
+      fd = android_hack_asset_fd (asset);
 
       if (fd == -1)
        {
-         /* The asset can't be accessed for some reason.  Try to
-            create a shared memory file descriptor.  */
-         fd = android_hack_asset_fd (asset);
-
-         if (fd == -1)
-           {
-             AAsset_close (asset);
-             errno = ENXIO;
-             return -1;
-           }
+         AAsset_close (asset);
+         errno = ENXIO;
+         return -1;
        }
 
       /* If O_CLOEXEC is specified, make the file descriptor close on