Update Android port

* INSTALL.android: Update.
* build-aux/ndk-build-helper-1.mk: Fix typo.
* configure.ac: Enable --with-json on Android.
* cross/ndk-build/ndk-build-shared-library.mk:
(NDK_CFLAGS_$(LOCAL_MODULE)):
(LOCAL_MODULE_FILENAME):
* cross/ndk-build/ndk-build-static-library.mk:
(ALL_OBJECT_FILES$(LOCAL_MODULE)):
(LOCAL_MODULE_FILENAME): Recursively resolve dependencies.
* cross/ndk-build/ndk-resolve.mk: New function.

* doc/emacs/android.texi (Android Startup): Document how Emacs
is dumped during initial startup.

* java/Makefile.in (filename): Fix build with multiple shared
libraries.
* java/README: Improve commentary.
* java/org/gnu/emacs/EmacsApplication.java (onCreate): Look and
set dump file.
* java/org/gnu/emacs/EmacsNative.java (EmacsNative): New
function getFingerprint.
* java/org/gnu/emacs/EmacsPreferencesActivity.java (onCreate):
Add option to erase the dump file.
* java/org/gnu/emacs/EmacsService.java (browseUrl): New
function.
* java/org/gnu/emacs/EmacsThread.java (run): Specify dump file
if found.
* lisp/loadup.el: Always dump during loadup on Android.

* lisp/net/browse-url.el (browse-url--browser-defcustom-type):
(browse-url-default-browser):
(browse-url-default-android-browser): New browse url type.

* m4/ndk-build.m4 (ndk_package_map): Map jansson to libjansson.
* src/android.c (struct android_emacs_service): New method
`browse_url'.
(getFingerprint): New function.
(android_init_emacs_service): Initialize new method.
(android_browse_url): New function.

* src/android.h: Update prototypes.

* src/androidselect.c (Fandroid_browse_url): New function.
(syms_of_androidselect): Define it.

* src/emacs.c (load_pdump): Don't look in fancy places on
Android.
* src/pdumper.c (Fdump_emacs_portable): Allow dumping while
interactive on Android.
(syms_of_pdumper): New variable `pdumper-fingerprint'.

* src/sfntfont-android.c (sfntfont_android_composite_bitmap):
Fix unused variables.
This commit is contained in:
Po Lu 2023-01-24 17:31:16 +08:00
parent 3267a2d6d2
commit 56e55a8008
23 changed files with 518 additions and 102 deletions

View file

@ -148,6 +148,14 @@ work:
(You must add LOCAL_EXPORT_CFLAGS := -I$(LOCAL_PATH) before
its Android.mk includes $(BUILD_STATIC_LIBRARY))
In addition, some Emacs dependencies provide `ndk-build' support
themselves:
libjansson - https://github.com/akheron/jansson
(You must add LOCAL_EXPORT_INCLUDES := $(LOCAL_C_INCLUDES) before
its Android.mk includes $(BUILD_SHARED_LIBRARY), then copy
android/jansson_config.h to android/jansson_private_config.h.)
We anticipate that most untested non-trivial ndk-build dependencies
will need adjustments in Emacs to work, as the Emacs build system
which emulates ndk-build is in an extremely early state.
@ -173,7 +181,7 @@ one awk script in build-awx, run during configure:
build-aux/ndk-module-extract.awk
six Makefiles in cross/ndk-build,
seven Makefiles in cross/ndk-build,
cross/ndk-build/ndk-build-shared-library.mk
cross/ndk-build/ndk-build-static-library.mk
@ -181,6 +189,7 @@ six Makefiles in cross/ndk-build,
cross/ndk-build/ndk-clear-vars.mk
cross/ndk-build/ndk-prebuilt-shared-library.mk
cross/ndk-build/ndk-prebuilt-static-library.mk
cross/ndk-build/ndk-resolve.mk
and finally, two more Makefiles in cross/ndk-build, generated by
configure:
@ -373,11 +382,27 @@ them. The name under which the module is linked is the same as the
Make target found on the sixth line of output from
build-aux/ndk-build-helper.mk.
However, none of the Makefiles in
cross/ndk-build/ndk-build-shared-library.mk perform any kind of
dependency resolution! Instead, they only define rules to build
individual modules, leaving dependency resolution up to the Makefiles
in the `build-aux' directory.
While the rules defined by the Makefiles in cross/ndk-build do not
have their dependencies as prerequisites (with the assumption that the
ndk-build.m4 and the Makefiles in build-aux have already added all of
the necessary targets to ndk-build.mk), dependency resolution is still
performed, as the CFLAGS and includes from dependencies must be
appended to the module's CFLAGS.
This is done by including cross/ndk-build/ndk-resolve.mk each time a
shared or static library module is going to be built. How is this
done?
First, ndk-resolve.mk saves the LOCAL_PATH, LOCAL_STATIC_LIBRARIES,
LOCAL_SHARED_LIBRARIES, LOCAL_EXPORT_CFLAGS and
LOCAL_EXPORT_C_INCLUDES from the module.
Next, ndk-resolve loops through the dependencies the module has
specified, appending its CFLAGS and includes to the command line for
the current module.
Then, that process is repeated for each such dependency which has not
already been resolved, until all dependencies have been resolved.
libpng is a very simple module, providing only a single shared object
module. This module is named libpng_emacs.so and is eventually built

View file

@ -33,7 +33,7 @@ NDK_$(LOCAL_MODULE)_SHARED_LIBRARIES := $(LOCAL_SHARED_LIBRARIES)
$(info Building $(build_kind))
$(info $(LOCAL_MODULE))
$(info $(addprefix $(ANDROID_MODULE_DIRECTORY)?,$(LOCAL_SRC_FILES) $(LOCAL_SRC_FILES$(EMACS_ABI))))
$(info $(addprefix $(ANDROID_MODULE_DIRECTORY)/,$(LOCAL_SRC_FILES) $(LOCAL_SRC_FILES$(EMACS_ABI))))
$(info $(foreach dir,$(LOCAL_EXPORT_C_INCLUDE_DIRS) $(LOCAL_EXPORT_C_INCLUDES),-I$(dir)))
$(info $(LOCAL_EXPORT_CFLAGS))

View file

@ -1045,6 +1045,7 @@ package will likely install on older systems but crash on startup.])
passthrough="$passthrough --with-png=$with_png"
passthrough="$passthrough --with-webp=$with_webp"
passthrough="$passthrough --with-gif=$with_gif"
passthrough="$passthrough --with-json=$with_json"
AS_IF([XCONFIGURE=android ANDROID_CC="$ANDROID_CC" \
ANDROID_SDK="$android_sdk" android_abi=$android_abi \
@ -1112,6 +1113,7 @@ if test "$ANDROID" = "yes"; then
with_png=no
with_webp=no
with_gif=no
with_json=no
fi
with_xml2=no
@ -1121,7 +1123,6 @@ if test "$ANDROID" = "yes"; then
with_libsystemd=no
with_cairo=no
with_imagemagick=no
with_json=no
with_tree_sitter=no
with_xft=no
with_harfbuzz=no

View file

@ -44,11 +44,13 @@ ALL_OBJECT_FILES$(LOCAL_MODULE) += $(call objname,$(LOCAL_MODULE),$(basename $(1
endef
NDK_CFLAGS_$(LOCAL_MODULE) := $(addprefix -I,$(addprefix $(LOCAL_PATH),$(LOCAL_C_INCLUDES)))
NDK_CFLAGS_$(LOCAL_MODULE) ::= -fPIC -iquote $(LOCAL_EXPORT_CFLAGS) $(LOCAL_PATH) $(LOCAL_CFLAGS)
NDK_LDFLAGS_$(LOCAL_MODULE) := $(LOCAL_LDLIBS)
NDK_LDFLAGS_$(LOCAL_MODULE) := $(LOCAL_LDFLAGS)
ALL_OBJECT_FILES_$(LOCAL_MODULE) :=
# Make sure to not add a prefix to local includes that already specify
# $(LOCAL_PATH).
NDK_CFLAGS_$(LOCAL_MODULE) := $(addprefix -I,$(LOCAL_C_INCLUDES))
NDK_CFLAGS_$(LOCAL_MODULE) += -fPIC -iquote $(LOCAL_PATH) $(LOCAL_EXPORT_CFLAGS) $(LOCAL_CFLAGS) $(LOCAL_CFLAGS$(NDK_BUILD_ARCH))
NDK_ASFLAGS_$(LOCAL_MODULE) := $(LOCAL_ASFLAGS) $(LOCAL_ASFLAGS_$(NDK_BUILD_ARCH))
NDK_LDFLAGS_$(LOCAL_MODULE) := $(LOCAL_LDLIBS) $(LOCAL_LDFLAGS)
ALL_OBJECT_FILES$(LOCAL_MODULE) :=
ifeq ($(NDK_BUILD_ARCH)$(NDK_ARM_MODE),armarm)
NDK_CFLAGS ::= -marm
@ -74,8 +76,17 @@ endif
LOCAL_MODULE_FILENAME := $(LOCAL_MODULE_FILENAME).so
# Record this module's dependencies and exported includes and CFLAGS,
# and then add that of its dependencies.
include ndk-resolve.mk
# Then define rules to build all objects.
ALL_SOURCE_FILES = $(LOCAL_SRC_FILES)
ALL_SOURCE_FILES = $(LOCAL_SRC_FILES) $(LOCAL_SRC_FILES_$(NDK_BUILD_ARCH))
# This defines all dependencies.
ALL_OBJECT_FILES$(LOCAL_MODULE) =
$(foreach source,$(ALL_SOURCE_FILES),$(eval $(call single-object-target,$(source))))
# Now define the rule to build the shared library.

View file

@ -43,11 +43,10 @@ endif
ALL_OBJECT_FILES$(LOCAL_MODULE) += $(call objname,$(LOCAL_MODULE),$(basename $(1)))
endef
NDK_CFLAGS_$(LOCAL_MODULE) := $(addprefix -I,$(addprefix $(LOCAL_PATH),$(LOCAL_C_INCLUDES)))
NDK_CFLAGS_$(LOCAL_MODULE) ::= -iquote $(LOCAL_PATH) $(LOCAL_EXPORT_CFLAGS) $(LOCAL_CFLAGS) $(LOCAL_CFLAGS_$(NDK_BUILD_ARCH))
NDK_ASFLAGS_$(LOCAL_MODULE) ::= $(LOCAL_ASFLAGS) $(LOCAL_ASFLAGS_$(NDK_BUILD_ARCH))
NDK_LDFLAGS_$(LOCAL_MODULE) := $(LOCAL_LDLIBS)
NDK_LDFLAGS_$(LOCAL_MODULE) := $(LOCAL_LDFLAGS)
NDK_CFLAGS_$(LOCAL_MODULE) := $(addprefix -I,$(LOCAL_C_INCLUDES))
NDK_CFLAGS_$(LOCAL_MODULE) += -iquote $(LOCAL_PATH) $(LOCAL_EXPORT_CFLAGS) $(LOCAL_CFLAGS) $(LOCAL_CFLAGS_$(NDK_BUILD_ARCH))
NDK_ASFLAGS_$(LOCAL_MODULE) := $(LOCAL_ASFLAGS) $(LOCAL_ASFLAGS_$(NDK_BUILD_ARCH))
NDK_LDFLAGS_$(LOCAL_MODULE) := $(LOCAL_LDLIBS) $(LOCAL_LDFLAGS)
ALL_OBJECT_FILES$(LOCAL_MODULE) :=
ifeq ($(NDK_BUILD_ARCH)$(NDK_ARM_MODE),armarm)
@ -70,6 +69,11 @@ endif
LOCAL_MODULE_FILENAME := $(LOCAL_MODULE_FILENAME).a
# Record this module's dependencies and exported includes and CFLAGS,
# and then add that of its dependencies.
include ndk-resolve.mk
# Then define rules to build all objects.
ALL_SOURCE_FILES = $(LOCAL_SRC_FILES) $(LOCAL_SRC_FILES_$(NDK_BUILD_ARCH))

View file

@ -0,0 +1,47 @@
# Copyright 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/>.
# ndk-build works by including a bunch of Makefiles which set
# variables, and then having those Makefiles include another makefile
# which actually builds targets.
# Save information.
NDK_LOCAL_PATH_$(LOCAL_MODULE) := $(LOCAL_PATH)
NDK_LOCAL_STATIC_LIBRARIES_$(LOCAL_MODULE) := $(LOCAL_STATIC_LIBRARIES) $(LOCAL_WHOLE_STATIC_LIBRARIES)
NDK_LOCAL_SHARED_LIBRARIES_$(LOCAL_MODULE) := $(LOCAL_SHARED_LIBRARIES)
NDK_LOCAL_EXPORT_CFLAGS_$(LOCAL_MODULE) := $(LOCAL_EXPORT_CFLAGS)
NDK_LOCAL_EXPORT_C_INCLUDES_$(LOCAL_MODULE) := $(LOCAL_EXPORT_C_INCLUDES)
# List of all dependencies resolved for this module thus far.
# Used to avoid infinite recursion.
NDK_RESOLVED_$(LOCAL_MODULE) :=
define ndk-resolve
ifeq ($(patsubst $(1),,$(NDK_RESOLVED$(LOCAL_MODULE))),$(NDK_RESOLVED$(LOCAL_MODULE)))
NDK_RESOLVED$(LOCAL_MODULE) += $(1)
NDK_CFLAGS_$(LOCAL_MODULE) += $(NDK_LOCAL_EXPORT_CFLAGS_$(1))
NDK_CFLAGS_$(LOCAL_MODULE) += $(addprefix -I,$(NDK_LOCAL_EXPORT_C_INCLUDES_$(1)))
$$(foreach module,$$(NDK_LOCAL_STATIC_LIBRARIES_$(1)),$$(eval $$(call ndk-resolve,$$(module))))
$$(foreach module,$$(NDK_LOCAL_SHARED_LIBRARIES_$(1)),$$(eval $$(call ndk-resolve,$$(module))))
endif
endef
$(foreach module,$(LOCAL_SHARED_LIBRARIES),$(eval $(call ndk-resolve,$(module))))
$(foreach module,$(LOCAL_STATIC_LIBRARIES) $(LOCAL_WHOLE_STATIC_LIBRARIES),$(eval $(call ndk-resolve,$(module))))

View file

@ -63,18 +63,18 @@ package manager. Instead, Emacs is compiled for Android on a
different operating system, with the resulting binaries packaged into
an archive, that is then transferred to the device and unpacked.
After being unpacked, Emacs instructs the system to display an
After being unpacked, Emacs instructs the system to display an
application icon on the desktop. Emacs then starts up once the
application icon is clicked.
@cindex ``adb logcat''
During startup, Emacs will display messages in the system log buffer;
reading that buffer requires the Android Debug Bridge (@code{adb})
utility to be installed on another computer; it cannot be read on the
computer running Android itself.
During startup, Emacs will display messages in the system log
buffer; reading that buffer requires the Android Debug Bridge
(@code{adb}) utility to be installed on another computer; it cannot be
read on the computer running Android itself.
After enabling the ``USB Debugging'' feature on the Android system,
After enabling the ``USB Debugging'' feature on the Android system,
and connecting it via USB to another system with the @code{adb}
utility installed, the log can be viewed by running the following
command on that other system:
@ -84,14 +84,31 @@ $ adb logcat | grep -E "(android_run_debug_thread|[Ee]macs)"
@end example
@cindex emacs -Q, android
Since Android has no command line, there is normally no way to specify
command-line arguments. However, Emacs can be started with the
equivalent of the @code{--quick} option (@pxref{Initial Options})
through a special preferences screen, which can be accessed through
the Emacs ``app info'' page in the system settings application.
Since Android has no command line, there is normally no way to
specify command-line arguments when starting Emacs. However, Emacs
can be started with the equivalent of the @code{--quick} option
(@pxref{Initial Options}) through a special preferences screen, which
can be accessed through the Emacs ``app info'' page in the system
settings application.
Consult the manufacturer of your device for more details, as how to do
this varies by device.
Consult the manufacturer of your device for more details, as how to
do this varies by device.
@cindex dumping, android
The first time any given copy of Emacs starts on a device, it spends
a while loading the preloaded Lisp files which normally come with
Emacs. This produces a ``dump file'' (@pxref{Initial Options}) in the
files directory, containing an identifier unique to this copy of
Emacs.
The next time that same copy of Emacs starts up, it simply loads the
preloaded Lisp files contained in that dump file, greatly improving
start up time.
However, if by some unforseen circumstance the dump file is
corrupted, Emacs can crash. If that happens, the dump file stored in
the Emacs files directory can be erased through the same preferences
screen.
@node Android File System
@section What files Emacs can access under Android

View file

@ -148,8 +148,7 @@ emacs.apk-in: $(CROSS_BINS) $(CROSS_LIBS) $(libsrc)/asset-directory-tool \
cp -f $$file install_temp/lib/$(ANDROID_ABI); \
fi \
done
$(foreach module,$(NDK_BUILD_SHARED), \
cp -f $(module) install_temp/lib/$(ANDROID_ABI))
cp -f $(NDK_BUILD_SHARED) install_temp/lib/$(ANDROID_ABI)
# Package everything. Specifying the assets on this command line is
# necessary for AAssetManager_getNextFileName to work on old versions
# of Android.

View file

@ -1,5 +1,11 @@
This directory holds the Java sources of the port of GNU Emacs to
Android-like systems.
Android-like systems, along with files needed to create an application
package out of them.
`emacs.keystore' is the signing key used to build Emacs. It is kept
here, and we encourage all people redistributing Emacs to use this
key. It holds no security value, and otherwise it will be impossible
to install different builds of Emacs on top of each other.
Please keep the Java code indented with tabs and formatted according
to the rules for C code in the GNU coding standards. Always use

View file

@ -19,9 +19,59 @@
package org.gnu.emacs;
import android.app.Application;
import java.io.File;
import java.io.FileFilter;
public class EmacsApplication extends Application
import android.app.Application;
import android.util.Log;
public class EmacsApplication extends Application implements FileFilter
{
/* This class currently does nothing. */
private static final String TAG = "EmacsApplication";
/* The name of the dump file to use. */
public static String dumpFileName;
@Override
public boolean
accept (File file)
{
return (!file.isDirectory ()
&& file.getName ().endsWith (".pdmp"));
}
@Override
public void
onCreate ()
{
File filesDirectory;
File[] allFiles;
String wantedDumpFile;
int i;
wantedDumpFile = ("emacs-" + EmacsNative.getFingerprint ()
+ ".pdmp");
Log.d (TAG, "onCreate: looking for " + wantedDumpFile);
/* Obtain a list of all files ending with ``.pdmp''. Then, look
for a file named ``emacs-<fingerprint>.pdmp'' and delete the
rest. */
filesDirectory = getFilesDir ();
allFiles = filesDirectory.listFiles (this);
/* Now try to find the right dump file. */
for (i = 0; i < allFiles.length; ++i)
{
if (allFiles[i].getName ().equals (wantedDumpFile))
dumpFileName = allFiles[i].getAbsolutePath ();
else
/* Delete this outdated dump file. */
allFiles[i].delete ();
}
Log.d (TAG, "onCreate: found " + dumpFileName);
super.onCreate ();
}
};

View file

@ -25,6 +25,10 @@
public class EmacsNative
{
/* Obtain the fingerprint of this build of Emacs. The fingerprint
can be used to determine the dump file name. */
public static native String getFingerprint ();
/* Set certain parameters before initializing Emacs. This proves
that libemacs.so is being loaded from Java code.

View file

@ -19,6 +19,8 @@
package org.gnu.emacs;
import java.io.File;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
@ -93,6 +95,31 @@ else if (Build.VERSION.SDK_INT
});
layout.addView (textView);
textView = new TextView (this);
textView.setPadding (8, 20, 20, 8);
params = new LinearLayout.LayoutParams (LayoutParams.MATCH_PARENT,
LayoutParams.WRAP_CONTENT);
textView.setLayoutParams (params);
textView.setText ("Erase dump file");
textView.setOnClickListener (new View.OnClickListener () {
@Override
public void
onClick (View view)
{
String wantedDumpFile;
File file;
wantedDumpFile = ("emacs-" + EmacsNative.getFingerprint ()
+ ".pdmp");
file = new File (getFilesDir (), wantedDumpFile);
if (file.exists ())
file.delete ();
}
});
layout.addView (textView);
super.onCreate (savedInstanceState);
}
};

View file

@ -43,6 +43,8 @@
import android.content.Intent;
import android.content.res.AssetManager;
import android.net.Uri;
import android.os.Build;
import android.os.Looper;
import android.os.IBinder;
@ -504,4 +506,27 @@ else if (apiLevel >= Build.VERSION_CODES.DONUT)
EmacsService.class));
}
}
/* Ask the system to open the specified URL.
Value is NULL upon success, or a string describing the error
upon failure. */
public String
browseUrl (String url)
{
Intent intent;
try
{
intent = new Intent (Intent.ACTION_VIEW, Uri.parse (url));
intent.setFlags (Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity (intent);
}
catch (Exception e)
{
return e.toString ();
}
return null;
}
};

View file

@ -38,10 +38,23 @@ public class EmacsThread extends Thread
{
String args[];
if (!startDashQ)
args = new String[] { "libandroid-emacs.so", };
if (EmacsApplication.dumpFileName == null)
{
if (!startDashQ)
args = new String[] { "libandroid-emacs.so", };
else
args = new String[] { "libandroid-emacs.so", "-Q", };
}
else
args = new String[] { "libandroid-emacs.so", "-Q", };
{
if (!startDashQ)
args = new String[] { "libandroid-emacs.so", "--dump-file",
EmacsApplication.dumpFileName, };
else
args = new String[] { "libandroid-emacs.so", "-Q",
"--dump-file",
EmacsApplication.dumpFileName, };
}
/* Run the native code now. */
EmacsNative.initEmacs (args);

View file

@ -550,66 +550,96 @@ lost after dumping")))
(if dump-mode
(let ((output (cond ((equal dump-mode "pdump") "emacs.pdmp")
((equal dump-mode "dump") "emacs")
((equal dump-mode "bootstrap") "emacs")
((equal dump-mode "pbootstrap") "bootstrap-emacs.pdmp")
(t (error "Unrecognized dump mode %s" dump-mode)))))
(when (and (featurep 'native-compile)
(equal dump-mode "pdump"))
;; Don't enable this before bootstrap is completed, as the
;; compiler infrastructure may not be usable yet.
(setq comp-enable-subr-trampolines t))
(message "Dumping under the name %s" output)
(condition-case ()
(delete-file output)
(file-error nil))
;; On MS-Windows, the current directory is not necessarily the
;; same as invocation-directory.
(let (success)
(unwind-protect
(let ((tmp-dump-mode dump-mode)
(dump-mode nil)
(lexical-binding nil))
(if (member tmp-dump-mode '("pdump" "pbootstrap"))
(dump-emacs-portable (expand-file-name output invocation-directory))
(dump-emacs output (if (eq system-type 'ms-dos)
"temacs.exe"
"temacs"))
(message "%d pure bytes used" pure-bytes-used))
(setq success t))
(unless success
(ignore-errors
(delete-file output)))))
;; Recompute NAME now, so that it isn't set when we dump.
(if (not (or (eq system-type 'ms-dos)
(eq system-type 'haiku) ;; BFS doesn't support hard links
;; Don't bother adding another name if we're just
;; building bootstrap-emacs.
(member dump-mode '("pbootstrap" "bootstrap"))))
(let ((name (format "emacs-%s.%d" emacs-version emacs-build-number))
(exe (if (eq system-type 'windows-nt) ".exe" "")))
(while (string-match "[^-+_.a-zA-Z0-9]+" name)
(setq name (concat (downcase (substring name 0 (match-beginning 0)))
"-"
(substring name (match-end 0)))))
(message "Adding name %s" (concat name exe))
;; When this runs on Windows, invocation-directory is not
;; necessarily the current directory.
(add-name-to-file (expand-file-name (concat "emacs" exe)
invocation-directory)
(expand-file-name (concat name exe)
invocation-directory)
t)
(when (equal dump-mode "pdump")
(message "Adding name %s" (concat name ".pdmp"))
(add-name-to-file (expand-file-name "emacs.pdmp"
(if (eq system-type 'android)
(progn
;; Dumping Emacs on Android works slightly differently from
;; everywhere else. The first time Emacs starts, Emacs dumps
;; itself to "emacs-%s.pdump", and then proceeds with loadup,
;; where %s is replaced by the dump fingerprint.
;; EmacsApplication.java removes any pdump files with a
;; different build fingerprint upon being created, which happens
;; the moment the Android system starts Emacs. Then, it passes
;; the appropriate "--dump-file" to libemacs.so as it starts.
(let ((temp-dir (getenv "TEMP"))
(dump-file-name (format "%semacs-%s.pdmp"
(file-name-as-directory "~")
pdumper-fingerprint))
(dump-temp-file-name (format "%s~emacs-%s.pdmp"
(file-name-as-directory "~")
pdumper-fingerprint)))
(unless (pdumper-stats)
(condition-case ()
(progn
(dump-emacs-portable dump-temp-file-name)
;; Move the dumped file to the actual dump file name.
(rename-file dump-temp-file-name dump-file-name)
;; Continue with loadup.
nil)
(error nil)))))
(if dump-mode
(let ((output (cond ((equal dump-mode "pdump") "emacs.pdmp")
((equal dump-mode "dump") "emacs")
((equal dump-mode "bootstrap") "emacs")
((equal dump-mode "pbootstrap") "bootstrap-emacs.pdmp")
(t (error "Unrecognized dump mode %s" dump-mode)))))
(when (and (featurep 'native-compile)
(equal dump-mode "pdump"))
;; Don't enable this before bootstrap is completed, as the
;; compiler infrastructure may not be usable yet.
(setq comp-enable-subr-trampolines t))
(message "Dumping under the name %s" output)
(condition-case ()
(delete-file output)
(file-error nil))
;; On MS-Windows, the current directory is not necessarily the
;; same as invocation-directory.
(let (success)
(unwind-protect
(let ((tmp-dump-mode dump-mode)
(dump-mode nil)
(lexical-binding nil))
(if (member tmp-dump-mode '("pdump" "pbootstrap"))
(dump-emacs-portable (expand-file-name output invocation-directory))
(dump-emacs output (if (eq system-type 'ms-dos)
"temacs.exe"
"temacs"))
(message "%d pure bytes used" pure-bytes-used))
(setq success t))
(unless success
(ignore-errors
(delete-file output)))))
;; Recompute NAME now, so that it isn't set when we dump.
(if (not (or (eq system-type 'ms-dos)
(eq system-type 'haiku) ;; BFS doesn't support hard links
;; There's no point keeping old dumps around for
;; the binary used to build Lisp on the build
;; machine.
(featurep 'android)
;; Don't bother adding another name if we're just
;; building bootstrap-emacs.
(member dump-mode '("pbootstrap" "bootstrap"))))
(let ((name (format "emacs-%s.%d" emacs-version emacs-build-number))
(exe (if (eq system-type 'windows-nt) ".exe" "")))
(while (string-match "[^-+_.a-zA-Z0-9]+" name)
(setq name (concat (downcase (substring name 0 (match-beginning 0)))
"-"
(substring name (match-end 0)))))
(message "Adding name %s" (concat name exe))
;; When this runs on Windows, invocation-directory is not
;; necessarily the current directory.
(add-name-to-file (expand-file-name (concat "emacs" exe)
invocation-directory)
(expand-file-name (concat name ".pdmp")
(expand-file-name (concat name exe)
invocation-directory)
t))))
(kill-emacs)))
t)
(when (equal dump-mode "pdump")
(message "Adding name %s" (concat name ".pdmp"))
(add-name-to-file (expand-file-name "emacs.pdmp"
invocation-directory)
(expand-file-name (concat name ".pdmp")
invocation-directory)
t))))
(kill-emacs))))
;; This file must be loaded each time Emacs is run from scratch, e.g., temacs.
;; So run the startup code now. First, remove `-l loadup' from args.

View file

@ -52,6 +52,7 @@
;; browse-url-xdg-open freedesktop.org xdg-open
;; browse-url-kde KDE konqueror (kfm)
;; browse-url-elinks Elinks Don't know (tried with 0.12.GIT)
;; browse-url-default-android-browser Android 2.3.3 (should work on 2.2 too)
;; eww-browse-url Emacs Web Wowser
;; Browsers can cache web pages so it may be necessary to tell them to
@ -173,6 +174,9 @@
,@(when (eq system-type 'darwin)
(list '(function-item :tag "Default macOS browser"
:value browse-url-default-macosx-browser)))
,@(when (eq system-type 'android)
(list '(function-item :tag "Default Android browser"
:value browse-url-default-android-browser)))
(function-item :tag "Default browser"
:value browse-url-default-browser)
(function :tag "Your own function")
@ -1057,6 +1061,8 @@ instead of `browse-url-new-window-flag'."
'browse-url-default-macosx-browser)
((featurep 'haiku)
'browse-url-default-haiku-browser)
((eq system-type 'android)
'browse-url-default-android-browser)
((browse-url-can-use-xdg-open) 'browse-url-xdg-open)
;;; ((executable-find browse-url-gnome-moz-program) 'browse-url-gnome-moz)
((executable-find browse-url-firefox-program) 'browse-url-firefox)
@ -1294,6 +1300,22 @@ Default to the URL around or before point."
(function-put 'browse-url-default-haiku-browser
'browse-url-browser-kind 'external)
(declare-function android-browse-url "androidselect.c")
;;;###autoload
(defun browse-url-default-android-browser (url &optional _new-window)
"Browse URL with the system default browser.
Default to the URL around or before point."
(interactive (browse-url-interactive-arg "URL: "))
(setq url (browse-url-encode-url url))
;; Make sure the URL starts with an appropriate scheme.
(unless (string-match "\\(.+\\):/" url)
(setq url (concat "http://" url)))
(android-browse-url url))
(function-put 'browse-url-default-android-browser
'browse-url-browser-kind 'external)
;;;###autoload
(defun browse-url-emacs (url &optional same-window)
"Ask Emacs to load URL into a buffer and show it in another window.

View file

@ -67,7 +67,7 @@ esac
# This is a map between pkg-config style package names and Android
# ones.
ndk_package_map="libwebpdemux:webpdemux libxml-2.0:libxml2"
ndk_package_map="libwebpdemux:webpdemux libxml-2.0:libxml2 jansson:libjansson"
# Replace ndk_module with the appropriate Android module name if it is
# found in ndk_package_map.

View file

@ -33,6 +33,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
#include <sys/param.h>
#include <assert.h>
#include <fingerprint.h>
#include "android.h"
#include "androidgui.h"
@ -95,6 +96,7 @@ struct android_emacs_service
jmethodID detect_mouse;
jmethodID name_keysym;
jmethodID sync;
jmethodID browse_url;
};
struct android_emacs_pixmap
@ -1294,6 +1296,18 @@ android_get_home_directory (void)
#pragma GCC diagnostic ignored "-Wmissing-prototypes"
#endif
JNIEXPORT jstring JNICALL
NATIVE_NAME (getFingerprint) (JNIEnv *env, jobject object)
{
char buffer[sizeof fingerprint * 2 + 1];
memset (buffer, 0, sizeof buffer);
hexbuf_digest (buffer, (char *) fingerprint,
sizeof fingerprint);
return (*env)->NewStringUTF (env, buffer);
}
JNIEXPORT void JNICALL
NATIVE_NAME (setEmacsParams) (JNIEnv *env, jobject object,
jobject local_asset_manager,
@ -1514,6 +1528,8 @@ android_init_emacs_service (void)
FIND_METHOD (detect_mouse, "detectMouse", "()Z");
FIND_METHOD (name_keysym, "nameKeysym", "(I)Ljava/lang/String;");
FIND_METHOD (sync, "sync", "()V");
FIND_METHOD (browse_url, "browseUrl", "(Ljava/lang/String;)"
"Ljava/lang/String;");
#undef FIND_METHOD
}
@ -4735,6 +4751,51 @@ android_project_image_nearest (struct android_image *image,
/* Other miscellaneous functions. */
/* Ask the system to start browsing the specified encoded URL. Upon
failure, return a string describing the error. Else, value is
nil. */
Lisp_Object
android_browse_url (Lisp_Object url)
{
jobject value, string;
Lisp_Object tem;
const char *buffer;
string = android_build_string (url);
value = (*android_java_env)->CallObjectMethod (android_java_env,
emacs_service,
service_class.browse_url,
string);
android_exception_check ();
ANDROID_DELETE_LOCAL_REF (string);
/* If no string was returned, return Qnil. */
if (!value)
return Qnil;
buffer = (*android_java_env)->GetStringUTFChars (android_java_env,
(jstring) value,
NULL);
android_exception_check ();
/* Otherwise, build the string describing the error. */
tem = build_string_from_utf8 (buffer);
(*android_java_env)->ReleaseStringUTFChars (android_java_env,
(jstring) value,
buffer);
/* And return it. */
ANDROID_DELETE_LOCAL_REF (value);
return tem;
}
#else /* ANDROID_STUBIFY */
/* X emulation functions for Android. */

View file

@ -107,6 +107,10 @@ extern void android_closedir (struct android_dir *);
/* Very miscellaneous functions. */
extern Lisp_Object android_browse_url (Lisp_Object);
#endif
/* JNI functions should not be built when Emacs is stubbed out for the

View file

@ -213,6 +213,25 @@ DEFUN ("android-clipboard-exists-p", Fandroid_clipboard_exists_p,
return rc ? Qt : Qnil;
}
DEFUN ("android-browse-url", Fandroid_browse_url,
Sandroid_browse_url, 1, 1, 0,
doc: /* Start the system web browser.
Then, point the web browser to URL, which should be a URL-encoded
URL with a scheme specified. Signal an error upon failure. */)
(Lisp_Object url)
{
Lisp_Object value;
CHECK_STRING (url);
value = android_browse_url (url);
/* Signal an error upon failure. */
if (!NILP (value))
signal_error ("Error browsing URL", value);
return Qnil;
}
void
@ -246,4 +265,5 @@ syms_of_androidselect (void)
defsubr (&Sandroid_set_clipboard);
defsubr (&Sandroid_get_clipboard);
defsubr (&Sandroid_clipboard_exists_p);
defsubr (&Sandroid_browse_url);
}

View file

@ -744,6 +744,8 @@ argmatch (char **argv, int argc, const char *sstr, const char *lstr,
}
}
#if !defined HAVE_ANDROID || defined ANDROID_STUBIFY
/* Find a name (absolute or relative) of the Emacs executable whose
name (as passed into this program) is ARGV0. Called early in
initialization by portable dumper loading code, so avoid Lisp and
@ -843,6 +845,8 @@ find_emacs_executable (char const *argv0, ptrdiff_t *candidate_size)
#endif /* !WINDOWSNT */
}
#endif
#ifdef HAVE_PDUMPER
static const char *
@ -875,6 +879,30 @@ dump_error_to_string (int result)
static char *
load_pdump (int argc, char **argv)
{
#if defined HAVE_ANDROID && !defined ANDROID_STUBIFY
char *dump_file = NULL;
int skip_args = 0, result;
while (skip_args < argc - 1)
{
if (argmatch (argv, argc, "-dump-file", "--dump-file", 6,
&dump_file, &skip_args)
|| argmatch (argv, argc, "--", NULL, 2, NULL, &skip_args))
break;
skip_args++;
}
if (!dump_file)
return argv[0];
result = pdumper_load (dump_file, argv[0]);
if (result != PDUMPER_LOAD_SUCCESS)
fatal ("could not load dump file \"%s\": %s",
dump_file, dump_error_to_string (result));
return argv[0];
#else
const char *const suffix = ".pdmp";
int result;
char *emacs_executable = argv[0];
@ -1067,6 +1095,7 @@ load_pdump (int argc, char **argv)
xfree (dump_file);
return emacs_executable;
#endif
}
#endif /* HAVE_PDUMPER */

View file

@ -4072,10 +4072,12 @@ types. */)
{
eassert (initialized);
#ifndef HAVE_ANDROID
if (! noninteractive)
error ("Dumping Emacs currently works only in batch mode. "
"If you'd like it to work interactively, please consider "
"contributing a patch to Emacs.");
#endif
if (will_dump_with_unexec_p ())
error ("This Emacs instance was started under the assumption "
@ -5842,6 +5844,10 @@ void
syms_of_pdumper (void)
{
#ifdef HAVE_PDUMPER
unsigned char desired[sizeof fingerprint];
int i;
char hexbuf[2 * sizeof fingerprint];
defsubr (&Sdump_emacs_portable);
defsubr (&Sdump_emacs_portable__sort_predicate);
defsubr (&Sdump_emacs_portable__sort_predicate_copied);
@ -5854,5 +5860,17 @@ syms_of_pdumper (void)
DEFSYM (Qdump_file_name, "dump-file-name");
DEFSYM (Qafter_pdump_load_hook, "after-pdump-load-hook");
defsubr (&Spdumper_stats);
for (i = 0; i < sizeof fingerprint; i++)
desired[i] = fingerprint[i];
hexbuf_digest (hexbuf, desired, sizeof desired);
DEFVAR_LISP ("pdumper-fingerprint", Vpdumper_fingerprint,
doc: /* The fingerprint of this Emacs binary.
It is a string that is supposed to be unique to each build of
Emacs. */);
Vpdumper_fingerprint = make_unibyte_string ((char *) hexbuf,
sizeof hexbuf);
#endif /* HAVE_PDUMPER */
}

View file

@ -320,7 +320,10 @@ sfntfont_android_composite_bitmap (unsigned char *restrict buffer,
{
unsigned int *src_row;
unsigned int *dst_row;
unsigned int i, src_y, x, src_x, max_x, dst_x, lim_x;
unsigned int i, src_y, x, src_x, max_x, dst_x;
#ifdef __aarch64__
unsigned int lim_x;
#endif
if ((intptr_t) dest & 3 || bitmap_info->stride & 3)
/* This shouldn't be possible as Android is supposed to align the
@ -353,10 +356,10 @@ sfntfont_android_composite_bitmap (unsigned char *restrict buffer,
src_x = x + (rect->x - text_rectangle->x);
dst_x = x + rect->x;
#ifdef __aarch64__
/* This is the largest value of src_x. */
lim_x = max_x + (rect->x - text_rectangle->x);
#ifdef __aarch64__
if (!sfntfont_android_over_8888 (src_row + src_x,
dst_row + dst_x,
src_row + lim_x,