mirror of
git://git.sv.gnu.org/emacs.git
synced 2026-01-13 23:10:26 -08:00
* INSTALL.android: Document how to install sqlite3. * build-aux/ndk-build-helper-1.mk (SYSTEM_LIBRARIES): * build-aux/ndk-build-helper-2.mk (SYSTEM_LIBRARIES): Add liblog and libandroid. * configure.ac (SQLITE3_LIBS, HAVE_SQLITE3) (HAVE_SQLITE3_LOAD_EXTENSION): Support on Android. (APKSIGNER): Look for this new required binary. * cross/ndk-build/ndk-build-shared-library.mk (objname): * cross/ndk-build/ndk-build-static-library.mk (objname): Avoid duplicate rules by prefixing objects with module type. * cross/ndk-build/ndk-build.mk.in (NDK_BUILD_SHARED): Fix definition. * cross/ndk-build/ndk-resolve.mk: (NDK_SO_EXTRA_FLAGS_$(LOCAL_MODULE)): Handle new system libraries. * doc/emacs/android.texi (Android File System): Document Android 10 system restriction. * java/AndroidManifest.xml.in: Target Android 33, not 28. * java/Makefile.in (SIGN_EMACS_V2, APKSIGNER): New variables. ($(APK_NAME)): Make sure to apply a ``version 2 signature'' to the package as well. * java/org/gnu/emacs/EmacsNative.java (EmacsNative): New argument apiLevel. * java/org/gnu/emacs/EmacsNoninteractive.java (main): * java/org/gnu/emacs/EmacsThread.java (run): Pass API level. * m4/ndk-build.m4 (ndk_package_mape): Add package mapping for sqlite3. * src/Makefile.in (SQLITE3_CFLAGS): New substition. (EMACS_CFLAGS): Add that variable. * src/android.c (android_api_level): New variable. (initEmacs): Set it. (android_file_access_p): Make static. (android_hack_asset_fd): Adjust for restrictions in Android 29 and later. (android_close_on_exec): New function. (android_open): Adjust to not duplicate file descriptor even if CLOEXEC. (android_faccessat): Use fstatat at-func emulation. * src/android.h: Update prototypes. * src/dired.c (file_name_completion_dirp): * src/fileio.c (file_access_p, Faccess_file): Now that sys_faccessat takes care of everything, stop calling android_file_access_p.
183 lines
5.6 KiB
Java
183 lines
5.6 KiB
Java
/* Communication module for Android terminals. -*- c-file-style: "GNU" -*-
|
|
|
|
Copyright (C) 2023 Free Software Foundation, Inc.
|
|
|
|
This file is part of GNU Emacs.
|
|
|
|
GNU Emacs is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or (at
|
|
your option) any later version.
|
|
|
|
GNU Emacs is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
|
|
|
|
package org.gnu.emacs;
|
|
|
|
import android.os.Looper;
|
|
import android.os.Build;
|
|
|
|
import android.content.Context;
|
|
import android.content.res.AssetManager;
|
|
|
|
import java.lang.reflect.Constructor;
|
|
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. */
|
|
|
|
@SuppressWarnings ("unchecked")
|
|
public class EmacsNoninteractive
|
|
{
|
|
private static String
|
|
getLibraryDirectory (Context context)
|
|
{
|
|
int apiLevel;
|
|
|
|
apiLevel = Build.VERSION.SDK_INT;
|
|
|
|
if (apiLevel >= Build.VERSION_CODES.GINGERBREAD)
|
|
return context.getApplicationInfo().nativeLibraryDir;
|
|
else if (apiLevel >= Build.VERSION_CODES.DONUT)
|
|
return context.getApplicationInfo().dataDir + "/lib";
|
|
|
|
return "/data/data/" + context.getPackageName() + "/lib";
|
|
}
|
|
|
|
public static void
|
|
main (String[] args)
|
|
{
|
|
Object activityThread, loadedApk;
|
|
Class activityThreadClass, loadedApkClass, contextImplClass;
|
|
Class compatibilityInfoClass;
|
|
Method method;
|
|
Context context;
|
|
AssetManager assets;
|
|
String filesDir, libDir, cacheDir;
|
|
|
|
Looper.prepare ();
|
|
context = null;
|
|
assets = null;
|
|
filesDir = libDir = cacheDir = null;
|
|
|
|
try
|
|
{
|
|
/* Get the activity thread. */
|
|
activityThreadClass = Class.forName ("android.app.ActivityThread");
|
|
|
|
/* Get the systemMain method. */
|
|
method = activityThreadClass.getMethod ("systemMain");
|
|
|
|
/* Create and attach the activity thread. */
|
|
activityThread = method.invoke (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)
|
|
{
|
|
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 = getLibraryDirectory (context);
|
|
cacheDir = context.getCacheDir ().getCanonicalPath ();
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
System.err.println ("Internal error: " + e);
|
|
System.err.println ("This means that the Android platform changed,");
|
|
System.err.println ("and that Emacs needs adjustments in order to");
|
|
System.err.println ("obtain required system internal resources.");
|
|
System.err.println ("Please report this bug to bug-gnu-emacs@gnu.org.");
|
|
|
|
System.exit (1);
|
|
}
|
|
|
|
EmacsNative.setEmacsParams (assets, filesDir,
|
|
libDir, cacheDir, 0.0f,
|
|
0.0f, null, null);
|
|
|
|
/* 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,
|
|
Build.VERSION.SDK_INT);
|
|
}
|
|
};
|