diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index ff328bb6..91cce47c 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -106,6 +106,11 @@ + diff --git a/app/src/main/java/com/termux/api/App.java b/app/src/main/java/com/termux/api/App.java new file mode 100644 index 00000000..d51b7e85 --- /dev/null +++ b/app/src/main/java/com/termux/api/App.java @@ -0,0 +1,217 @@ +package com.termux.api; + +import android.app.Application; +import android.content.Intent; +import android.net.LocalServerSocket; +import android.net.LocalSocket; + +import com.termux.api.util.TermuxApiLogger; + +import java.io.BufferedWriter; +import java.io.DataInputStream; +import java.io.OutputStreamWriter; +import java.nio.charset.StandardCharsets; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class App extends Application +{ + public static final String LISTEN_ADDRESS = "com.termux.api://listen"; + private static final Pattern EXTRA_STRING = Pattern.compile("(-e|--es|--esa) +([^ ]+) +\"(.*?)(? { + try (LocalServerSocket listen = new LocalServerSocket(LISTEN_ADDRESS)) { + while (true) { + try (LocalSocket con = listen.accept(); + DataInputStream in = new DataInputStream(con.getInputStream()); + BufferedWriter out = new BufferedWriter(new OutputStreamWriter(con.getOutputStream()))) { + // only accept connections from Termux programs + if (con.getPeerCredentials().getUid() != getApplicationInfo().uid) { + continue; + } + try { + //System.out.println("connection"); + int length = in.readUnsignedShort(); + byte[] b = new byte[length]; + in.readFully(b); + String cmdline = new String(b, StandardCharsets.UTF_8); + + //System.out.println(cmdline.replaceAll("--es socket_input \".*?\"","").replaceAll("--es socket_output \".*?\"","")); + HashMap stringExtras = new HashMap<>(); + HashMap stringArrayExtras = new HashMap<>(); + HashMap booleanExtras = new HashMap<>(); + HashMap intExtras = new HashMap<>(); + HashMap floatExtras = new HashMap<>(); + HashMap intArrayExtras = new HashMap<>(); + HashMap longArrayExtras = new HashMap<>(); + boolean err = false; + + // extract and remove the string extras first, so another argument embedded in a string isn't counted as an argument + Matcher m = EXTRA_STRING.matcher(cmdline); + while (m.find()) { + String option = m.group(1); + if ("-e".equals(option) || "--es".equals(option)) { + // unescape " + stringExtras.put(m.group(2), Objects.requireNonNull(m.group(3)).replaceAll("\\\\\"","\"")); + } else { + // split the list + String[] list = Objects.requireNonNull(m.group(3)).split("(? e : stringExtras.entrySet()) { + i.putExtra(e.getKey(), e.getValue()); + } + for (Map.Entry e : stringArrayExtras.entrySet()) { + i.putExtra(e.getKey(), e.getValue()); + } + for (Map.Entry e : intExtras.entrySet()) { + i.putExtra(e.getKey(), e.getValue()); + } + for (Map.Entry e : booleanExtras.entrySet()) { + i.putExtra(e.getKey(), e.getValue()); + } + for (Map.Entry e : floatExtras.entrySet()) { + i.putExtra(e.getKey(), e.getValue()); + } + for (Map.Entry e : intArrayExtras.entrySet()) { + i.putExtra(e.getKey(), e.getValue()); + } + for (Map.Entry e : longArrayExtras.entrySet()) { + i.putExtra(e.getKey(), e.getValue()); + } + getApplicationContext().sendOrderedBroadcast(i, null); + // send a null byte as a sign that the arguments have been successfully received, parsed and the broadcast receiver is called + con.getOutputStream().write(0); + con.getOutputStream().flush(); + } catch (Exception e) { + TermuxApiLogger.error("Error parsing arguments", e); + out.write("Exception in the plugin\n"); + out.flush(); + } + } + } + } catch (Exception e) { + TermuxApiLogger.error("Error listening for connections", e); + } + }).start(); + } + +} diff --git a/app/src/main/java/com/termux/api/KeepAliveService.java b/app/src/main/java/com/termux/api/KeepAliveService.java new file mode 100644 index 00000000..666ca27a --- /dev/null +++ b/app/src/main/java/com/termux/api/KeepAliveService.java @@ -0,0 +1,21 @@ +package com.termux.api; + +import android.app.Service; +import android.content.Intent; +import android.os.IBinder; + +import androidx.annotation.Nullable; + +public class KeepAliveService extends Service +{ + @Override + public int onStartCommand(Intent intent, int flags, int startId) { + return Service.START_STICKY; + } + + @Nullable + @Override + public IBinder onBind(Intent intent) { + return null; + } +} diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 3c789642..682868c7 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -11,6 +11,6 @@ &TERMUX_API_APP_NAME; Share with Grant permission - + This service keeps Termux:API running in the background for faster startup of termux-* commands. This app needs the following permission(s):\n