root/src/android-emacs.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. main

     1 /* Android initialization for GNU Emacs.
     2 
     3 Copyright (C) 2023 Free Software Foundation, Inc.
     4 
     5 This file is part of GNU Emacs.
     6 
     7 GNU Emacs is free software: you can redistribute it and/or modify
     8 it under the terms of the GNU General Public License as published by
     9 the Free Software Foundation, either version 3 of the License, or (at
    10 your option) any later version.
    11 
    12 GNU Emacs is distributed in the hope that it will be useful,
    13 but WITHOUT ANY WARRANTY; without even the implied warranty of
    14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    15 GNU General Public License for more details.
    16 
    17 You should have received a copy of the GNU General Public License
    18 along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.  */
    19 
    20 #include <config.h>
    21 #include <stdio.h>
    22 #include <alloca.h>
    23 #include <string.h>
    24 #include <unistd.h>
    25 
    26 /* android-emacs is a wrapper around /system/bin/app_process(64).
    27    It invokes app_process(64) with the right class path and then
    28    starts org.gnu.emacs.EmacsNoninteractive.
    29 
    30    The main function in that class tries to load an activity thread
    31    and obtain a context and asset manager before calling
    32    android_emacs_init, which is required for Emacs to find required
    33    preloaded Lisp.  */
    34 
    35 int
    36 main (int argc, char **argv)
    37 {
    38   char **args;
    39   int i;
    40   char *bootclasspath, *emacs_class_path;
    41 
    42   /* Allocate enough to hold the arguments to app_process.  */
    43   args = alloca ((10 + argc) * sizeof *args);
    44 
    45   /* Clear args.  */
    46   memset (args, 0, (10 + argc) * sizeof *args);
    47 
    48   /* First, figure out what program to start.  */
    49 #if defined __x86_64__ || defined __aarch64__
    50   args[0] = (char *) "/system/bin/app_process64";
    51 #else
    52   args[0] = (char *) "/system/bin/app_process";
    53 #endif
    54 
    55   /* Machines with ART require the boot classpath to be manually
    56      specified.  Machines with Dalvik however refuse to do so, as they
    57      open the jars inside the BOOTCLASSPATH environment variable at
    58      startup, resulting in the following crash:
    59 
    60      W/dalvikvm( 1608): Refusing to reopen boot DEX
    61      '/system/framework/core.jar'
    62      W/dalvikvm( 1608): Refusing to reopen boot DEX
    63      '/system/framework/bouncycastle.jar'
    64      E/dalvikvm( 1608): Too many exceptions during init (failed on
    65      'Ljava/io/IOException;' 'Re-opening BOOTCLASSPATH DEX files is
    66      not allowed')
    67      E/dalvikvm( 1608): VM aborting  */
    68 
    69 #if HAVE_DECL_ANDROID_GET_DEVICE_API_LEVEL
    70   if (android_get_device_api_level () < 21)
    71     {
    72       bootclasspath = NULL;
    73       goto skip_setup;
    74     }
    75 #else
    76   if (__ANDROID_API__ < 21)
    77     {
    78       bootclasspath = NULL;
    79       goto skip_setup;
    80     }
    81 #endif
    82 
    83   /* Next, obtain the boot class path.  */
    84   bootclasspath = getenv ("BOOTCLASSPATH");
    85 
    86   if (!bootclasspath)
    87     {
    88       fprintf (stderr, "The BOOTCLASSPATH environment variable"
    89                " is not set.  As a result, Emacs does not know"
    90                " how to start app_process.\n"
    91                "This is likely a change in the Android platform."
    92                "  Please report this to bug-gnu-emacs@gnu.org.\n");
    93       return 1;
    94     }
    95 
    96  skip_setup:
    97 
    98   /* And the Emacs class path.  */
    99   emacs_class_path = getenv ("EMACS_CLASS_PATH");
   100 
   101   if (!emacs_class_path)
   102     {
   103       fprintf (stderr, "EMACS_CLASS_PATH not set."
   104                "  Please make sure Emacs is being started"
   105                " from within a running copy of Emacs.\n");
   106       return 1;
   107     }
   108 
   109   if (bootclasspath)
   110     {
   111       if (asprintf (&bootclasspath, "-Djava.class.path=%s:%s",
   112                     bootclasspath, emacs_class_path) < 0)
   113         {
   114           perror ("asprintf");
   115           return 1;
   116         }
   117     }
   118   else
   119     {
   120       if (asprintf (&bootclasspath, "-Djava.class.path=%s",
   121                     emacs_class_path) < 0)
   122         {
   123           perror ("asprintf");
   124           return 1;
   125         }
   126     }
   127 
   128   args[1] = bootclasspath;
   129   args[2] = (char *) "/system/bin";
   130 
   131 #if HAVE_DECL_ANDROID_GET_DEVICE_API_LEVEL
   132   /* I don't know exactly when --nice-name was introduced; this is
   133      just a guess.  */
   134   if (android_get_device_api_level () >= 26)
   135     {
   136       args[3] = (char *) "--nice-name=emacs";
   137       args[4] = (char *) "org.gnu.emacs.EmacsNoninteractive";
   138 
   139       /* Arguments from here on are passed to main in
   140          EmacsNoninteractive.java.  */
   141       args[5] = argv[0];
   142 
   143       /* Now copy the rest of the arguments over.  */
   144       for (i = 1; i < argc; ++i)
   145         args[5 + i] = argv[i];
   146     }
   147   else
   148     {
   149 #endif
   150       args[3] = (char *) "org.gnu.emacs.EmacsNoninteractive";
   151 
   152       /* Arguments from here on are passed to main in
   153          EmacsNoninteractive.java.  */
   154       args[4] = argv[0];
   155 
   156       /* Now copy the rest of the arguments over.  */
   157       for (i = 1; i < argc; ++i)
   158         args[4 + i] = argv[i];
   159 #if HAVE_DECL_ANDROID_GET_DEVICE_API_LEVEL
   160     }
   161 #endif
   162 
   163   /* Finally, try to start the app_process.  */
   164   execvp (args[0], args);
   165 
   166   /* If exit fails, return an error indication.  */
   167   perror ("exec");
   168   return 1;
   169 }

/* [<][>][^][v][top][bottom][index][help] */