mirror of
https://git.savannah.gnu.org/git/emacs.git
synced 2024-11-21 06:55:39 +00:00
Fix build and running on Android 2.2
* INSTALL.android: Document that Android 2.2 is now supported, with caveats. * configure.ac (ANDROID_MIN_SDK, ANDROID_SDK_18_OR_EARLIER) (SYSTEM_TYPE, ANDROID_STUBIFY, SIZEOF_LONG): Correctly detect things missing on Android 2.2. * java/Makefile.in (ANDROID_JAR, JARSIGNER_FLAGS): * java/debug.sh (jdb, gdbserver, line): * java/org/gnu/emacs/EmacsApplication.java (findDumpFile): * java/org/gnu/emacs/EmacsService.java (onCreate): * java/org/gnu/emacs/EmacsThread.java (EmacsThread, run): Run parameter initialization on main thread. * src/android-asset.h (struct android_asset_manager) (struct android_asset, AAssetManager_fromJava, AAssetManager_open) (AAsset_close, android_asset_create_stream) (android_asset_read_internal, AAsset_openFileDescriptor) (AAsset_getLength, AAsset_getBuffer, AAsset_read): New file. * src/android.c (android_user_full_name, android_hack_asset_fd) (android_check_compressed_file): Implement for Android 2.2. * src/process.c (Fprocess_send_eof): Don't call tcdrain if unavailable. * src/sfntfont-android.c (system_font_directories): Fix compiler warning. * src/sfntfont.c (sfntfont_read_cmap): Correctly test rc of emacs_open. * src/textconv.c (handle_pending_conversion_events_1): Mark buffer UNINIT.
This commit is contained in:
parent
759e6a24ab
commit
88afd96e36
@ -91,9 +91,18 @@ for, and the include directories specify the paths to the relevant
|
||||
Android headers. In addition, it may be necessary to specify
|
||||
"-gdwarf-2", due to a bug in the Android NDK.
|
||||
|
||||
Emacs is known to build for Android 2.2 (API version 8) or later, and
|
||||
run on Android 2.3 or later. It is supposed to run on Android 2.2 as
|
||||
well.
|
||||
Even older versions of the Android SDK do not require the extra
|
||||
`-isystem' directives.
|
||||
|
||||
Emacs is known to run on Android 2.2 (API version 8) or later, with
|
||||
the NDK r10b or later. We wanted to make Emacs work on even older
|
||||
versions of Android, but they are missing the required JNI graphics
|
||||
library that allows Emacs to display text from C code.
|
||||
|
||||
Due to an extremely nasty bug in the Android 2.2 system, the generated
|
||||
Emacs package cannot be compressed in builds for Android 2.2. As a
|
||||
result, the Emacs package will be approximately 100 megabytes larger
|
||||
than a compressed package for a newer version of Android.
|
||||
|
||||
DEBUG AND RELEASE BUILDS
|
||||
|
||||
|
23
configure.ac
23
configure.ac
@ -1044,11 +1044,18 @@ package will likely install on older systems but crash on startup.])
|
||||
# Now tell java/Makefile if Emacs is being built for Android 4.3 or
|
||||
# earlier.
|
||||
ANDROID_SDK_18_OR_EARLIER=
|
||||
if test "$android_sdk" -lt "18"; then
|
||||
if test "$android_sdk" -le "18"; then
|
||||
ANDROID_SDK_18_OR_EARLIER=yes
|
||||
fi
|
||||
AC_SUBST([ANDROID_SDK_18_OR_EARLIER])
|
||||
|
||||
# Likewise for Android 2.2.
|
||||
ANDROID_SDK_8_OR_EARLIER=
|
||||
if test "$android_sdk" -le "8"; then
|
||||
ANDROID_SDK_8_OR_EARLIER=yes
|
||||
fi
|
||||
AC_SUBST([ANDROID_SDK_8_OR_EARLIER])
|
||||
|
||||
# Save confdefs.h and config.log for now.
|
||||
mv -f confdefs.h _confdefs.h
|
||||
mv -f config.log _config.log
|
||||
@ -2251,6 +2258,10 @@ AC_DEFINE_UNQUOTED([SYSTEM_TYPE], ["$SYSTEM_TYPE"],
|
||||
[The type of system you are compiling for; sets 'system-type'.])
|
||||
AC_SUBST([SYSTEM_TYPE])
|
||||
|
||||
# Check for pw_gecos in struct passwd; this is known to be missing on
|
||||
# Android.
|
||||
|
||||
AC_CHECK_MEMBERS([struct passwd.pw_gecos], [], [], [#include <pwd.h>])
|
||||
|
||||
pre_PKG_CONFIG_CFLAGS=$CFLAGS
|
||||
pre_PKG_CONFIG_LIBS=$LIBS
|
||||
@ -2487,7 +2498,13 @@ for Android, but all API calls need to be stubbed out])
|
||||
ANDROID_CFLAGS="$ANDROID_CFLAGS -ftree-vectorize"
|
||||
|
||||
# Link with libraries required for Android support.
|
||||
ANDROID_LIBS="-landroid -llog -ljnigraphics"
|
||||
# API 9 and later require `-landroid' for the asset manager.
|
||||
# API 8 uses an emulation via the JNI.
|
||||
if test "$ANDROID_SDK" -lt "9"; then
|
||||
ANDROID_LIBS="-llog -ljnigraphics"
|
||||
else
|
||||
ANDROID_LIBS="-landroid -llog -ljnigraphics"
|
||||
fi
|
||||
|
||||
# This is required to make the system load emacs.apk's libpng
|
||||
# (among others) instead of the system's own. But it doesn't work
|
||||
@ -5610,7 +5627,7 @@ OLD_LIBS=$LIBS
|
||||
LIBS="$LIB_PTHREAD $LIB_MATH $LIBS"
|
||||
AC_CHECK_FUNCS([accept4 fchdir gethostname \
|
||||
getrusage get_current_dir_name \
|
||||
lrand48 random rint trunc \
|
||||
lrand48 random rint tcdrain trunc \
|
||||
select getpagesize setlocale newlocale \
|
||||
getrlimit setrlimit shutdown \
|
||||
pthread_sigmask strsignal setitimer \
|
||||
|
@ -39,6 +39,7 @@ JARSIGNER_FLAGS =
|
||||
ANDROID_JAR = @ANDROID_JAR@
|
||||
ANDROID_ABI = @ANDROID_ABI@
|
||||
ANDROID_SDK_18_OR_EARLIER = @ANDROID_SDK_18_OR_EARLIER@
|
||||
ANDROID_SDK_8_OR_EARLIER = @ANDROID_SDK_8_OR_EARLIER@
|
||||
|
||||
WARN_JAVAFLAGS = -Xlint:deprecation
|
||||
JAVAFLAGS = -classpath "$(ANDROID_JAR):." -target 1.7 -source 1.7 \
|
||||
@ -53,6 +54,16 @@ else
|
||||
JARSIGNER_FLAGS =
|
||||
endif
|
||||
|
||||
# When building Emacs for Android 2.2, assets must not be compressed.
|
||||
# Otherwise, the asset manager fails to extract files larger than 1
|
||||
# MB.
|
||||
|
||||
ifneq (,$(ANDROID_SDK_8_OR_EARLIER))
|
||||
AAPT_ASSET_ARGS = -0 ""
|
||||
else
|
||||
AAPT_ASSET_ARGS =
|
||||
endif
|
||||
|
||||
SIGN_EMACS = -keystore emacs.keystore -storepass emacs1 $(JARSIGNER_FLAGS)
|
||||
SIGN_EMACS_V2 = sign --v2-signing-enabled --ks emacs.keystore \
|
||||
--debuggable-apk-permitted --ks-pass pass:emacs1
|
||||
@ -192,7 +203,8 @@ emacs.apk-in: install_temp install_temp/assets/directory-tree \
|
||||
# of Android. Make sure not to generate R.java, as it's already been
|
||||
# generated.
|
||||
$(AM_V_AAPT) $(AAPT) p -I "$(ANDROID_JAR)" -F $@ \
|
||||
-f -M AndroidManifest.xml -A install_temp/assets \
|
||||
-f -M AndroidManifest.xml $(AAPT_ASSET_ARGS) \
|
||||
-A install_temp/assets \
|
||||
-S res -J install_temp
|
||||
$(AM_V_SILENT) pushd install_temp &> /dev/null; \
|
||||
$(AAPT) add ../$@ `find lib -type f`; \
|
||||
|
@ -32,6 +32,7 @@ jdb_port=64013
|
||||
jdb=no
|
||||
attach_existing=no
|
||||
gdbserver=
|
||||
gdb=gdb
|
||||
|
||||
while [ $# -gt 0 ]; do
|
||||
case "$1" in
|
||||
@ -51,6 +52,7 @@ while [ $# -gt 0 ]; do
|
||||
echo " --port PORT run the GDB server on a specific port"
|
||||
echo " --jdb-port PORT run the JDB server on a specific port"
|
||||
echo " --jdb run JDB instead of GDB"
|
||||
echo " --gdb use specified GDB binary"
|
||||
echo " --attach-existing attach to an existing process"
|
||||
echo " --gdbserver BINARY upload and use the specified gdbserver binary"
|
||||
echo " --help print this message"
|
||||
@ -65,6 +67,10 @@ while [ $# -gt 0 ]; do
|
||||
"--jdb" )
|
||||
jdb=yes
|
||||
;;
|
||||
"--gdb" )
|
||||
shift
|
||||
gdb=$1
|
||||
;;
|
||||
"--gdbserver" )
|
||||
shift
|
||||
gdbserver=$1
|
||||
@ -355,4 +361,4 @@ fi
|
||||
|
||||
# Finally, start gdb with any extra arguments needed.
|
||||
cd "$oldpwd"
|
||||
gdb --eval-command "target remote localhost:$gdb_port" $gdbargs
|
||||
$gdb --eval-command "target remote localhost:$gdb_port" $gdbargs
|
||||
|
@ -49,6 +49,7 @@ public class EmacsApplication extends Application
|
||||
for a file named ``emacs-<fingerprint>.pdmp'' and delete the
|
||||
rest. */
|
||||
filesDirectory = context.getFilesDir ();
|
||||
|
||||
allFiles = filesDirectory.listFiles (new FileFilter () {
|
||||
@Override
|
||||
public boolean
|
||||
|
@ -180,11 +180,11 @@ else if (apiLevel >= Build.VERSION_CODES.DONUT)
|
||||
public void
|
||||
onCreate ()
|
||||
{
|
||||
AssetManager manager;
|
||||
final AssetManager manager;
|
||||
Context app_context;
|
||||
String filesDir, libDir, cacheDir, classPath;
|
||||
double pixelDensityX;
|
||||
double pixelDensityY;
|
||||
final String filesDir, libDir, cacheDir, classPath;
|
||||
final double pixelDensityX;
|
||||
final double pixelDensityY;
|
||||
|
||||
SERVICE = this;
|
||||
handler = new Handler (Looper.getMainLooper ());
|
||||
@ -210,13 +210,18 @@ invocation of app_process (through android-emacs) can
|
||||
Log.d (TAG, "Initializing Emacs, where filesDir = " + filesDir
|
||||
+ ", libDir = " + libDir + ", and classPath = " + classPath);
|
||||
|
||||
EmacsNative.setEmacsParams (manager, filesDir, libDir,
|
||||
cacheDir, (float) pixelDensityX,
|
||||
(float) pixelDensityY,
|
||||
classPath, this);
|
||||
|
||||
/* Start the thread that runs Emacs. */
|
||||
thread = new EmacsThread (this, needDashQ);
|
||||
thread = new EmacsThread (this, new Runnable () {
|
||||
@Override
|
||||
public void
|
||||
run ()
|
||||
{
|
||||
EmacsNative.setEmacsParams (manager, filesDir, libDir,
|
||||
cacheDir, (float) pixelDensityX,
|
||||
(float) pixelDensityY,
|
||||
classPath, EmacsService.this);
|
||||
}
|
||||
}, needDashQ);
|
||||
thread.start ();
|
||||
}
|
||||
catch (IOException exception)
|
||||
|
@ -28,11 +28,16 @@ public class EmacsThread extends Thread
|
||||
/* Whether or not Emacs should be started -Q. */
|
||||
private boolean startDashQ;
|
||||
|
||||
/* Runnable run to initialize Emacs. */
|
||||
private Runnable paramsClosure;
|
||||
|
||||
public
|
||||
EmacsThread (EmacsService service, boolean startDashQ)
|
||||
EmacsThread (EmacsService service, Runnable paramsClosure,
|
||||
boolean startDashQ)
|
||||
{
|
||||
super ("Emacs main thread");
|
||||
this.startDashQ = startDashQ;
|
||||
this.paramsClosure = paramsClosure;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -46,6 +51,8 @@ public class EmacsThread extends Thread
|
||||
else
|
||||
args = new String[] { "libandroid-emacs.so", "-Q", };
|
||||
|
||||
paramsClosure.run ();
|
||||
|
||||
/* Run the native code now. */
|
||||
EmacsNative.initEmacs (args, EmacsApplication.dumpFileName,
|
||||
Build.VERSION.SDK_INT);
|
||||
|
423
src/android-asset.h
Normal file
423
src/android-asset.h
Normal file
@ -0,0 +1,423 @@
|
||||
/* Android initialization for GNU Emacs.
|
||||
|
||||
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/>. */
|
||||
|
||||
#include <android/log.h>
|
||||
|
||||
/* This file contains an emulation of the Android asset manager API
|
||||
used on builds for Android 2.2. It is included by android.c
|
||||
whenever appropriate.
|
||||
|
||||
The replacements in this file are not thread safe and must only be
|
||||
called from the creating thread. */
|
||||
|
||||
struct android_asset_manager
|
||||
{
|
||||
/* JNI environment. */
|
||||
JNIEnv *env;
|
||||
|
||||
/* Asset manager class and functions. */
|
||||
jclass class;
|
||||
jmethodID open_fd;
|
||||
|
||||
/* Asset file descriptor class and functions. */
|
||||
jclass fd_class;
|
||||
jmethodID get_length;
|
||||
jmethodID create_input_stream;
|
||||
jmethodID close;
|
||||
|
||||
/* Input stream class and functions. */
|
||||
jclass input_stream_class;
|
||||
jmethodID read;
|
||||
jmethodID stream_close;
|
||||
|
||||
/* Associated asset manager object. */
|
||||
jobject asset_manager;
|
||||
};
|
||||
|
||||
typedef struct android_asset_manager AAssetManager;
|
||||
|
||||
struct android_asset
|
||||
{
|
||||
/* The asset manager. */
|
||||
AAssetManager *manager;
|
||||
|
||||
/* The length of the asset, or -1. */
|
||||
jlong length;
|
||||
|
||||
/* The asset file descriptor and input stream. */
|
||||
jobject fd, stream;
|
||||
|
||||
/* The mode. */
|
||||
int mode;
|
||||
};
|
||||
|
||||
typedef struct android_asset AAsset;
|
||||
|
||||
static AAssetManager *
|
||||
AAssetManager_fromJava (JNIEnv *env, jobject java_manager)
|
||||
{
|
||||
AAssetManager *manager;
|
||||
jclass temp;
|
||||
|
||||
manager = malloc (sizeof *manager);
|
||||
|
||||
if (!manager)
|
||||
return NULL;
|
||||
|
||||
manager->env = env;
|
||||
manager->asset_manager
|
||||
= (*env)->NewGlobalRef (env, java_manager);
|
||||
|
||||
if (!manager->asset_manager)
|
||||
{
|
||||
free (manager);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
manager->class
|
||||
= (*env)->FindClass (env, "android/content/res/AssetManager");
|
||||
assert (manager->class);
|
||||
|
||||
manager->open_fd
|
||||
= (*env)->GetMethodID (env, manager->class, "openFd",
|
||||
"(Ljava/lang/String;)"
|
||||
"Landroid/content/res/AssetFileDescriptor;");
|
||||
assert (manager->open);
|
||||
|
||||
manager->fd_class
|
||||
= (*env)->FindClass (env, "android/content/res/AssetFileDescriptor");
|
||||
assert (manager->fd_class);
|
||||
|
||||
manager->get_length
|
||||
= (*env)->GetMethodID (env, manager->fd_class, "getLength",
|
||||
"()J");
|
||||
assert (manager->get_length);
|
||||
|
||||
manager->create_input_stream
|
||||
= (*env)->GetMethodID (env, manager->fd_class,
|
||||
"createInputStream",
|
||||
"()Ljava/io/FileInputStream;");
|
||||
assert (manager->create_input_stream);
|
||||
|
||||
manager->close
|
||||
= (*env)->GetMethodID (env, manager->fd_class,
|
||||
"close", "()V");
|
||||
assert (manager->close);
|
||||
|
||||
manager->input_stream_class
|
||||
= (*env)->FindClass (env, "java/io/InputStream");
|
||||
assert (manager->input_stream_class);
|
||||
|
||||
manager->read
|
||||
= (*env)->GetMethodID (env, manager->input_stream_class,
|
||||
"read", "([B)I");
|
||||
assert (manager->read);
|
||||
|
||||
manager->stream_close
|
||||
= (*env)->GetMethodID (env, manager->input_stream_class,
|
||||
"close", "()V");
|
||||
assert (manager->stream_close);
|
||||
|
||||
/* Now convert all the class references to global ones. */
|
||||
temp = manager->class;
|
||||
manager->class
|
||||
= (*env)->NewGlobalRef (env, temp);
|
||||
assert (manager->class);
|
||||
(*env)->DeleteLocalRef (env, temp);
|
||||
temp = manager->fd_class;
|
||||
manager->fd_class
|
||||
= (*env)->NewGlobalRef (env, temp);
|
||||
assert (manager->fd_class);
|
||||
(*env)->DeleteLocalRef (env, temp);
|
||||
temp = manager->input_stream_class;
|
||||
manager->input_stream_class
|
||||
= (*env)->NewGlobalRef (env, temp);
|
||||
assert (manager->input_stream_class);
|
||||
(*env)->DeleteLocalRef (env, temp);
|
||||
|
||||
/* Return the asset manager. */
|
||||
return manager;
|
||||
}
|
||||
|
||||
enum
|
||||
{
|
||||
AASSET_MODE_STREAMING = 0,
|
||||
AASSET_MODE_BUFFER = 1,
|
||||
};
|
||||
|
||||
static AAsset *
|
||||
AAssetManager_open (AAssetManager *manager, const char *c_name,
|
||||
int mode)
|
||||
{
|
||||
jobject desc;
|
||||
jstring name;
|
||||
AAsset *asset;
|
||||
|
||||
/* Push a local frame. */
|
||||
asset = NULL;
|
||||
|
||||
(*(manager->env))->PushLocalFrame (manager->env, 3);
|
||||
|
||||
if ((*(manager->env))->ExceptionCheck (manager->env))
|
||||
goto fail;
|
||||
|
||||
/* Encoding issues can be ignored for now as there are only ASCII
|
||||
file names in Emacs. */
|
||||
name = (*(manager->env))->NewStringUTF (manager->env, c_name);
|
||||
|
||||
if (!name)
|
||||
goto fail;
|
||||
|
||||
/* Now try to open an ``AssetFileDescriptor''. */
|
||||
desc = (*(manager->env))->CallObjectMethod (manager->env,
|
||||
manager->asset_manager,
|
||||
manager->open_fd,
|
||||
name);
|
||||
|
||||
if (!desc)
|
||||
goto fail;
|
||||
|
||||
/* Allocate the asset. */
|
||||
asset = calloc (1, sizeof *asset);
|
||||
|
||||
if (!asset)
|
||||
{
|
||||
(*(manager->env))->CallVoidMethod (manager->env,
|
||||
desc,
|
||||
manager->close);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Pop the local frame and return desc. */
|
||||
desc = (*(manager->env))->NewGlobalRef (manager->env, desc);
|
||||
|
||||
if (!desc)
|
||||
goto fail;
|
||||
|
||||
(*(manager->env))->PopLocalFrame (manager->env, NULL);
|
||||
|
||||
asset->manager = manager;
|
||||
asset->length = -1;
|
||||
asset->fd = desc;
|
||||
asset->mode = mode;
|
||||
|
||||
return asset;
|
||||
|
||||
fail:
|
||||
(*(manager->env))->ExceptionClear (manager->env);
|
||||
(*(manager->env))->PopLocalFrame (manager->env, NULL);
|
||||
free (asset);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static AAsset *
|
||||
AAsset_close (AAsset *asset)
|
||||
{
|
||||
JNIEnv *env;
|
||||
|
||||
env = asset->manager->env;
|
||||
|
||||
(*env)->CallVoidMethod (asset->manager->env,
|
||||
asset->fd,
|
||||
asset->manager->close);
|
||||
(*env)->DeleteGlobalRef (asset->manager->env,
|
||||
asset->fd);
|
||||
|
||||
if (asset->stream)
|
||||
{
|
||||
(*env)->CallVoidMethod (asset->manager->env,
|
||||
asset->stream,
|
||||
asset->manager->stream_close);
|
||||
(*env)->DeleteGlobalRef (asset->manager->env,
|
||||
asset->stream);
|
||||
}
|
||||
|
||||
free (asset);
|
||||
}
|
||||
|
||||
/* Create an input stream associated with the given ASSET. Set
|
||||
ASSET->stream to its global reference.
|
||||
|
||||
Value is 1 upon failure, else 0. ASSET must not already have an
|
||||
input stream. */
|
||||
|
||||
static int
|
||||
android_asset_create_stream (AAsset *asset)
|
||||
{
|
||||
jobject stream;
|
||||
JNIEnv *env;
|
||||
|
||||
env = asset->manager->env;
|
||||
stream
|
||||
= (*env)->CallObjectMethod (env, asset->fd,
|
||||
asset->manager->create_input_stream);
|
||||
|
||||
if (!stream)
|
||||
{
|
||||
(*env)->ExceptionClear (env);
|
||||
return 1;
|
||||
}
|
||||
|
||||
asset->stream
|
||||
= (*env)->NewGlobalRef (env, stream);
|
||||
|
||||
if (!asset->stream)
|
||||
{
|
||||
(*env)->ExceptionClear (env);
|
||||
(*env)->DeleteLocalRef (env, stream);
|
||||
return 1;
|
||||
}
|
||||
|
||||
(*env)->DeleteLocalRef (env, stream);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Read NBYTES from the specified asset into the given BUFFER;
|
||||
|
||||
Internally, allocate a Java byte array containing 4096 elements and
|
||||
copy the data to and from that array.
|
||||
|
||||
Value is the number of bytes actually read, 0 at EOF, or -1 upon
|
||||
failure, in which case errno is set accordingly. If NBYTES is
|
||||
zero, behavior is undefined. */
|
||||
|
||||
static int
|
||||
android_asset_read_internal (AAsset *asset, int nbytes, char *buffer)
|
||||
{
|
||||
jbyteArray stash;
|
||||
JNIEnv *env;
|
||||
jint bytes_read, total;
|
||||
|
||||
/* Allocate a suitable amount of storage. Either nbytes or 4096,
|
||||
whichever is larger. */
|
||||
env = asset->manager->env;
|
||||
stash = (*env)->NewByteArray (env, MIN (nbytes, 4096));
|
||||
|
||||
if (!stash)
|
||||
{
|
||||
(*env)->ExceptionClear (env);
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Try to create an input stream. */
|
||||
|
||||
if (!asset->stream
|
||||
&& android_asset_create_stream (asset))
|
||||
{
|
||||
(*env)->DeleteLocalRef (env, stash);
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Start reading. */
|
||||
|
||||
total = 0;
|
||||
|
||||
while (nbytes)
|
||||
{
|
||||
bytes_read = (*env)->CallIntMethod (env, asset->stream,
|
||||
asset->manager->read,
|
||||
stash);
|
||||
|
||||
/* Detect error conditions. */
|
||||
|
||||
if ((*env)->ExceptionCheck (env))
|
||||
goto out;
|
||||
|
||||
/* Detect EOF. */
|
||||
|
||||
if (bytes_read == -1)
|
||||
goto out;
|
||||
|
||||
/* Finally write out the amount that was read. */
|
||||
bytes_read = MIN (bytes_read, nbytes);
|
||||
(*env)->GetByteArrayRegion (env, stash, 0, bytes_read, buffer);
|
||||
|
||||
buffer += bytes_read;
|
||||
total += bytes_read;
|
||||
nbytes -= bytes_read;
|
||||
}
|
||||
|
||||
/* Make sure the value of nbytes still makes sense. */
|
||||
assert (nbytes >= 0);
|
||||
|
||||
out:
|
||||
(*env)->ExceptionClear (env);
|
||||
(*env)->DeleteLocalRef (env, stash);
|
||||
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)
|
||||
{
|
||||
JNIEnv *env;
|
||||
|
||||
if (asset->length != -1)
|
||||
return asset->length;
|
||||
|
||||
env = asset->manager->env;
|
||||
asset->length
|
||||
= (*env)->CallLongMethod (env, asset->fd,
|
||||
asset->manager->get_length);
|
||||
return asset->length;
|
||||
}
|
||||
|
||||
static char *
|
||||
AAsset_getBuffer (AAsset *asset)
|
||||
{
|
||||
long length;
|
||||
char *buffer;
|
||||
|
||||
length = AAsset_getLength (asset);
|
||||
|
||||
if (!length)
|
||||
return NULL;
|
||||
|
||||
buffer = malloc (length);
|
||||
|
||||
if (!buffer)
|
||||
return NULL;
|
||||
|
||||
if (android_asset_read_internal (asset, length, buffer)
|
||||
!= length)
|
||||
{
|
||||
xfree (buffer);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
static size_t
|
||||
AAsset_read (AAsset *asset, void *buffer, size_t size)
|
||||
{
|
||||
return android_asset_read_internal (asset, MIN (size, INT_MAX),
|
||||
buffer);
|
||||
}
|
@ -32,6 +32,9 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
|
||||
#include <sys/mman.h>
|
||||
#include <sys/param.h>
|
||||
|
||||
/* Old NDK versions lack MIN and MAX. */
|
||||
#include <minmax.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <fingerprint.h>
|
||||
|
||||
@ -49,8 +52,13 @@ bool android_init_gui;
|
||||
|
||||
#ifndef ANDROID_STUBIFY
|
||||
|
||||
#if __ANDROID_API__ >= 9
|
||||
#include <android/asset_manager.h>
|
||||
#include <android/asset_manager_jni.h>
|
||||
#else
|
||||
#include "android-asset.h"
|
||||
#endif
|
||||
|
||||
#include <android/bitmap.h>
|
||||
#include <android/log.h>
|
||||
|
||||
@ -907,10 +915,14 @@ android_is_directory (const char *dir)
|
||||
char *
|
||||
android_user_full_name (struct passwd *pw)
|
||||
{
|
||||
#ifdef HAVE_STRUCT_PASSWD_PW_GECOS
|
||||
if (!pw->pw_gecos)
|
||||
return (char *) "Android user";
|
||||
|
||||
return pw->pw_gecos;
|
||||
#else
|
||||
return "Android user";
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Given a real file name, return the part that describes its asset
|
||||
@ -1048,6 +1060,60 @@ android_file_access_p (const char *name, int amode)
|
||||
static int
|
||||
android_hack_asset_fd (AAsset *asset)
|
||||
{
|
||||
#if __ANDROID_API__ < 9
|
||||
int fd;
|
||||
char filename[PATH_MAX];
|
||||
size_t size;
|
||||
void *mem;
|
||||
|
||||
/* Assets must be small enough to fit in size_t, if off_t is
|
||||
larger. */
|
||||
size = AAsset_getLength (asset);
|
||||
|
||||
/* Get an unlinked file descriptor from a file in the cache
|
||||
directory, which is guaranteed to only be written to by Emacs.
|
||||
Creating an asset file descriptor doesn't work on these old
|
||||
Android versions. */
|
||||
|
||||
snprintf (filename, PATH_MAX, "%s/%s.%d",
|
||||
android_cache_dir, "temp-unlinked",
|
||||
getpid ());
|
||||
fd = open (filename, O_CREAT | O_RDWR | O_TRUNC,
|
||||
S_IRUSR | S_IWUSR);
|
||||
|
||||
if (fd < 1)
|
||||
return -1;
|
||||
|
||||
if (unlink (filename))
|
||||
goto fail;
|
||||
|
||||
if (ftruncate (fd, size))
|
||||
goto fail;
|
||||
|
||||
mem = mmap (NULL, size, PROT_WRITE, MAP_SHARED, fd, 0);
|
||||
if (mem == MAP_FAILED)
|
||||
{
|
||||
__android_log_print (ANDROID_LOG_ERROR, __func__,
|
||||
"mmap: %s", strerror (errno));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (AAsset_read (asset, mem, size) != size)
|
||||
{
|
||||
/* Too little was read. Close the file descriptor and
|
||||
report an error. */
|
||||
__android_log_print (ANDROID_LOG_ERROR, __func__,
|
||||
"AAsset_read: %s", strerror (errno));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
munmap (mem, size);
|
||||
return fd;
|
||||
|
||||
fail:
|
||||
close (fd);
|
||||
return -1;
|
||||
#else
|
||||
int fd, rc;
|
||||
unsigned char *mem;
|
||||
size_t size;
|
||||
@ -1172,10 +1238,11 @@ android_hack_asset_fd (AAsset *asset)
|
||||
/* Return anyway even if munmap fails. */
|
||||
munmap (mem, size);
|
||||
return fd;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Read two bytes from FD and see if they are ``PK'', denoting ZIP
|
||||
archive compressed data.
|
||||
archive compressed data. If FD is -1, return -1.
|
||||
|
||||
If they are not, rewind the file descriptor to offset 0.
|
||||
|
||||
@ -1187,6 +1254,9 @@ android_check_compressed_file (int fd)
|
||||
{
|
||||
char bytes[2];
|
||||
|
||||
if (fd == -1)
|
||||
return -1;
|
||||
|
||||
if (read (fd, bytes, 2) != 2)
|
||||
goto lseek_back;
|
||||
|
||||
|
@ -7248,7 +7248,7 @@ process has been transmitted to the serial port. */)
|
||||
send_process (proc, "\004", 1, Qnil);
|
||||
else if (EQ (XPROCESS (proc)->type, Qserial))
|
||||
{
|
||||
#ifndef WINDOWSNT
|
||||
#if !defined WINDOWSNT && defined HAVE_TCDRAIN
|
||||
if (tcdrain (XPROCESS (proc)->outfd) != 0)
|
||||
report_file_error ("Failed tcdrain", Qnil);
|
||||
#endif /* not WINDOWSNT */
|
||||
|
@ -51,7 +51,7 @@ struct sfntfont_android_scanline_buffer
|
||||
/* Array of directories to search for system fonts. */
|
||||
static char *system_font_directories[] =
|
||||
{
|
||||
"/system/fonts",
|
||||
(char *) "/system/fonts",
|
||||
/* This should be filled in by init_sfntfont_android. */
|
||||
(char[PATH_MAX]) { },
|
||||
};
|
||||
|
@ -953,7 +953,7 @@ sfntfont_read_cmap (struct sfnt_font_desc *desc,
|
||||
/* Pick a character map and place it in *CMAP. */
|
||||
fd = emacs_open (desc->path, O_RDONLY, 0);
|
||||
|
||||
if (fd < 1)
|
||||
if (fd < 0)
|
||||
return;
|
||||
|
||||
font = sfnt_read_table_directory (fd);
|
||||
|
@ -989,7 +989,7 @@ handle_pending_conversion_events_1 (struct frame *f,
|
||||
{
|
||||
Lisp_Object data;
|
||||
enum text_conversion_operation operation;
|
||||
struct buffer *buffer;
|
||||
struct buffer *buffer UNINIT;
|
||||
struct window *w;
|
||||
specpdl_ref count;
|
||||
unsigned long token;
|
||||
|
Loading…
Reference in New Issue
Block a user