diff options
author | Po Lu <luangruo@yahoo.com> | 2024-07-14 12:46:23 +0800 |
---|---|---|
committer | Po Lu <luangruo@yahoo.com> | 2024-07-14 12:46:23 +0800 |
commit | b00fc31dd1d4543f8b017e8d7fef7686cd430bcc (patch) | |
tree | bc88bc250ff41feed860c4d2c90a3a2990de09d3 | |
parent | 04bf3172f03497eef6985311c90fd6557ace42b2 (diff) | |
download | emacs-b00fc31dd1d4543f8b017e8d7fef7686cd430bcc.tar.gz emacs-b00fc31dd1d4543f8b017e8d7fef7686cd430bcc.tar.bz2 emacs-b00fc31dd1d4543f8b017e8d7fef7686cd430bcc.zip |
Do not set LD_LIBRARY_PATH during Android initialization
* doc/emacs/android.texi (Android Environment): Adjust
documentation to match.
* java/org/gnu/emacs/EmacsNoninteractive.java (main1): New
function. Remove initialization of EmacsNative hither.
(main): Acquire an ApplicationInfo or LoadedApk, as the case may
be on the host system, derive a ClassLoader from the result, and
load and call `main1' from within this class loader.
* src/android-emacs.c (main):
* src/android.c (setEmacsParams): Do not override
LD_LIBRARY_PATH or set EMACS_LD_LIBRARY_PATH. This enables
Emacs to execute subprocesses in certain "fortified" Android
systems, amongst other things.
-rw-r--r-- | doc/emacs/android.texi | 22 | ||||
-rw-r--r-- | java/org/gnu/emacs/EmacsNoninteractive.java | 250 | ||||
-rw-r--r-- | src/android-emacs.c | 11 | ||||
-rw-r--r-- | src/android.c | 11 |
4 files changed, 147 insertions, 147 deletions
diff --git a/doc/emacs/android.texi b/doc/emacs/android.texi index 2d95f5c8fef..edcbb971b98 100644 --- a/doc/emacs/android.texi +++ b/doc/emacs/android.texi @@ -378,20 +378,18 @@ definition documents, so your mileage may vary. @cindex EMACS_CLASS_PATH environment variable, Android Even when the location of the @command{libandroid-emacs.so} command is -known in advance, special configuration is required to run Emacs from +known in advance, special preparation is required to run Emacs from elsewhere than a subprocess of an existing Emacs session, as it must be made to understand the location of resources and shared libraries in or extracted from the installed application package. The OS command @command{pm path org.gnu.emacs} will print the location of the -application package, and the adjacent @file{lib} directory will hold -shared libraries extracted from the same, though the said command must -be invoked in a peculiar manner to satisfy system restrictions on -communication between pseudoterminal devices created by user -applications and system services such as the package manager, which is -to say, with the standard IO streams redirected to a real file or a -pipe. Such values, once established, must be specified in the -environment variables @code{EMACS_CLASS_PATH} and -@code{EMACS_LD_LIBRARY_PATH}, so that this sample shell script may be +application package, though the said command must be invoked in a +peculiar manner to satisfy system restrictions on communication between +pseudoterminal devices created by user applications and system services +such as the package manager, which is to say, with the standard IO +streams redirected to a real file or a pipe. This value, once +established, must be specified in the environment variables +@code{EMACS_CLASS_PATH}, so that this sample shell script may be installed as @code{emacs} in any location that is accessible: @example @@ -400,7 +398,6 @@ installed as @code{emacs} in any location that is accessible: package_name=`pm path org.gnu.emacs 2>/dev/null </dev/null \ | sed 's/^package://'` emacs= -ld_path= EMACS_CLASS_PATH=$package_name for libdir in `dirname $package_name`/lib/*; do @@ -409,10 +406,7 @@ for libdir in `dirname $package_name`/lib/*; do && emacs="$libdir"/libandroid-emacs.so done -EMACS_LD_LIBRARY_PATH=$ld_path - export EMACS_CLASS_PATH -export EMACS_LD_LIBRARY_PATH test -x "$emacs" || exit 1 exec $emacs "$@@" @end example diff --git a/java/org/gnu/emacs/EmacsNoninteractive.java b/java/org/gnu/emacs/EmacsNoninteractive.java index ba23399cb3e..9f2b9fa8b56 100644 --- a/java/org/gnu/emacs/EmacsNoninteractive.java +++ b/java/org/gnu/emacs/EmacsNoninteractive.java @@ -30,37 +30,69 @@ import java.lang.reflect.Method; /* Noninteractive Emacs. - This is the class that libandroid-emacs.so starts. - libandroid-emacs.so figures out the system classpath, then starts - dalvikvm with the framework jars. - - At that point, dalvikvm calls main, which sets up the main looper, - creates an ActivityThread and attaches it to the main thread. - - Then, it obtains an application context for the LoadedApk in the - application thread. - - Finally, it obtains the necessary context specific objects and - initializes Emacs. */ + When started, libandroid-emacs.so invokes `app_process(64)' with a + command line placing Emacs's classes.dex file in the JVM class path, + which in turn transfers control to `main'. `main' creates a context, + which may be likened to a connection to the system server, and a + class loader derived from Emacs's application package, which it loads + beforehand. From this class loader, it loads another instance of + itself, and invokes `main1', to ensure the execution of + `EmacsNative''s static initializer within the application class + loader, where a proper library search path is in effect. */ @SuppressWarnings ("unchecked") public final class EmacsNoninteractive { + /* Prepare Emacs for startup and call `initEmacs'. This function is + called in an instance of `EmacsNoninteractive' loaded by the APK + ClassLoader acquired in `main', which guarantees that shared + libraries in the APK will be considered in resolving shared + libraries for `EmacsNative'. */ + + public static void + main1 (String[] args, Context context) + throws Exception + { + AssetManager assets; + String filesDir, libDir, cacheDir; + + /* Don't actually start the looper or anything. Instead, obtain + an AssetManager. */ + assets = context.getAssets (); + + /* Now configure Emacs. The class path should already be set. */ + + filesDir = context.getFilesDir ().getCanonicalPath (); + libDir = EmacsService.getLibraryDirectory (context); + cacheDir = context.getCacheDir ().getCanonicalPath (); + EmacsNative.setEmacsParams (assets, filesDir, + libDir, cacheDir, 0.0f, + 0.0f, 0.0f, null, null, + Build.VERSION.SDK_INT); + + /* Now find the dump file that Emacs should use, if it has already + been dumped. */ + EmacsApplication.findDumpFile (context); + + /* Start Emacs. */ + EmacsNative.initEmacs (args, EmacsApplication.dumpFileName); + } + public static void main (String[] args) { Object activityThread, loadedApk; Class activityThreadClass, loadedApkClass, contextImplClass; - Class compatibilityInfoClass; + Class compatibilityInfoClass, emacsNoninteractiveClass; Method method; Context context; - AssetManager assets; - String filesDir, libDir, cacheDir; + ClassLoader classLoader; Looper.prepare (); + context = null; - assets = null; - filesDir = libDir = cacheDir = null; + loadedApkClass = null; + classLoader = null; try { @@ -72,7 +104,6 @@ public final class EmacsNoninteractive /* Create and attach the activity thread. */ activityThread = method.invoke (null); - context = null; /* Now get an LoadedApk. */ @@ -82,99 +113,88 @@ public final class EmacsNoninteractive } catch (ClassNotFoundException exception) { - /* Android 2.2 has no LoadedApk class, but fortunately it - does not need to be used, since contexts can be - directly created. */ + /* Android 2.2 has no LoadedApk class; the several following + statements will load a context and an + ActivityThread.PackageInfo, as is appropriate on this + system. */ + } - loadedApkClass = null; - contextImplClass = Class.forName ("android.app.ContextImpl"); + /* Get a LoadedApk or ActivityThread.PackageInfo. How to do + this varies by Android version. On Android 2.3.3 and + earlier, there is no ``compatibilityInfo'' argument to + getPackageInfo. */ - 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); + 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", + (Context.CONTEXT_INCLUDE_CODE + | Context.CONTEXT_IGNORE_SECURITY)); } + 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, (Context.CONTEXT_INCLUDE_CODE + | Context.CONTEXT_IGNORE_SECURITY)); + } + + if (loadedApk == null) + throw new RuntimeException ("getPackageInfo returned NULL"); + + /* If loadedApkClass remains NULL, substitute the class of + the object returned by getPackageInfo. */ + if (loadedApkClass == null) + loadedApkClass = loadedApk.getClass (); - /* If the context has not already been created, then do what - is appropriate for newer versions of Android. */ + /* Now, get a context. */ + contextImplClass = Class.forName ("android.app.ContextImpl"); - if (context == null) + try { - /* 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); - } + 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 (); - - /* Now configure Emacs. The class path should already be set. */ + /* Retrieve the LoadedApk's class loader and execute the + remaining portion of the start-up process within its version + of EmacsNoninteractive, which will indicate to the system + that it must load shared libraries from the APK's library + search path. */ - filesDir = context.getFilesDir ().getCanonicalPath (); - libDir = EmacsService.getLibraryDirectory (context); - cacheDir = context.getCacheDir ().getCanonicalPath (); + method = loadedApkClass.getDeclaredMethod ("getClassLoader"); + classLoader = (ClassLoader) method.invoke (loadedApk); } catch (Exception e) { @@ -188,16 +208,20 @@ public final class EmacsNoninteractive System.exit (1); } - EmacsNative.setEmacsParams (assets, filesDir, - libDir, cacheDir, 0.0f, - 0.0f, 0.0f, null, null, - Build.VERSION.SDK_INT); - - /* Now find the dump file that Emacs should use, if it has already - been dumped. */ - EmacsApplication.findDumpFile (context); - - /* Start Emacs. */ - EmacsNative.initEmacs (args, EmacsApplication.dumpFileName); + try + { + emacsNoninteractiveClass + = classLoader.loadClass ("org.gnu.emacs.EmacsNoninteractive"); + method = emacsNoninteractiveClass.getMethod ("main1", String[].class, + Context.class); + method.setAccessible (true); + method.invoke (null, args, context); + } + catch (Exception e) + { + System.err.println ("Internal error during startup: " + e); + e.printStackTrace (); + System.exit (1); + } } }; diff --git a/src/android-emacs.c b/src/android-emacs.c index d68734da1bd..28b46ca1a4b 100644 --- a/src/android-emacs.c +++ b/src/android-emacs.c @@ -37,7 +37,7 @@ main (int argc, char **argv) { char **args; int i; - char *bootclasspath, *emacs_class_path, *ld_library_path; + char *bootclasspath, *emacs_class_path; /* Allocate enough to hold the arguments to app_process. */ args = alloca ((10 + argc) * sizeof *args); @@ -63,15 +63,6 @@ main (int argc, char **argv) return 1; } - /* Restore LD_LIBRARY_PATH to its original value, the app library - directory, to guarantee that it is possible for Java to find the - Emacs C code later. */ - - ld_library_path = getenv ("EMACS_LD_LIBRARY_PATH"); - - if (ld_library_path) - setenv ("LD_LIBRARY_PATH", ld_library_path, 1); - if (asprintf (&bootclasspath, "-Djava.class.path=%s", emacs_class_path) < 0) { diff --git a/src/android.c b/src/android.c index f90ebc04925..3c96867a6b5 100644 --- a/src/android.c +++ b/src/android.c @@ -1338,7 +1338,7 @@ NATIVE_NAME (setEmacsParams) (JNIEnv *env, jobject object, int pipefd[2]; pthread_t thread; - const char *java_string; + const char *java_string, *tem; struct stat statb; #ifdef THREADS_ENABLED @@ -1491,15 +1491,6 @@ NATIVE_NAME (setEmacsParams) (JNIEnv *env, jobject object, EmacsNoninteractive can be found. */ setenv ("EMACS_CLASS_PATH", android_class_path, 1); - /* Set LD_LIBRARY_PATH to an appropriate value. */ - setenv ("LD_LIBRARY_PATH", android_lib_dir, 1); - - /* EMACS_LD_LIBRARY_PATH records the location of the app library - directory. android-emacs refers to this, since users have valid - reasons for changing LD_LIBRARY_PATH to a value that precludes - the possibility of Java locating libemacs later. */ - setenv ("EMACS_LD_LIBRARY_PATH", android_lib_dir, 1); - /* If the system is Android 5.0 or later, set LANG to en_US.utf8, which is understood by the C library. In other instances set it to C, a meaningless value, for good measure. */ |