mirror of
https://github.com/masscollaborationlabs/emacs.git
synced 2025-07-04 03:13:24 +00:00
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.
This commit is contained in:
parent
04bf3172f0
commit
b00fc31dd1
4 changed files with 147 additions and 147 deletions
|
@ -30,37 +30,69 @@
|
|||
|
||||
/* 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");
|
||||
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 ();
|
||||
|
||||
/* 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
|
||||
= contextImplClass.getDeclaredMethod ("createPackageContext",
|
||||
String.class,
|
||||
int.class);
|
||||
method.setAccessible (true);
|
||||
context = (Context) method.invoke (context, "org.gnu.emacs",
|
||||
0);
|
||||
}
|
||||
|
||||
/* If the context has not already been created, then do what
|
||||
is appropriate for newer versions of Android. */
|
||||
/* 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. */
|
||||
|
||||
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 ();
|
||||
|
||||
/* Now configure Emacs. The class path should already be set. */
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue