77import android .content .BroadcastReceiver .PendingResult ;
88import android .content .Context ;
99import android .content .Intent ;
10+ import android .content .pm .ApplicationInfo ;
1011import android .net .LocalSocket ;
1112import android .net .LocalSocketAddress ;
13+ import android .net .LocalSocketAddress .Namespace ;
1214import android .os .ParcelFileDescriptor ;
1315import android .util .JsonWriter ;
1416
17+ import androidx .annotation .NonNull ;
18+
19+ import com .termux .shared .android .PackageUtils ;
20+ import com .termux .shared .file .FileUtils ;
1521import com .termux .shared .logger .Logger ;
1622import com .termux .shared .termux .TermuxConstants ;
1723import com .termux .shared .termux .plugins .TermuxPluginUtils ;
2329import java .io .OutputStream ;
2430import java .io .PrintWriter ;
2531import java .nio .charset .StandardCharsets ;
32+ import java .util .ArrayList ;
33+ import java .util .Arrays ;
34+ import java .util .List ;
2635
2736public abstract class ResultReturner {
2837
2938 @ SuppressLint ("StaticFieldLeak" )
30- private static Context context ;
39+ public static Context context ;
3140
3241 private static final String LOG_TAG = "ResultReturner" ;
3342
3443 /**
35- * An extra intent parameter which specifies a linux abstract namespace socket address where output from the API
44+ * An extra intent parameter which specifies a unix socket address where output from the API
3645 * call should be written.
3746 */
3847 private static final String SOCKET_OUTPUT_EXTRA = "socket_output" ;
3948
4049 /**
41- * An extra intent parameter which specifies a linux abstract namespace socket address where input to the API call
50+ * An extra intent parameter which specifies a unix socket address where input to the API call
4251 * can be read from.
4352 */
4453 private static final String SOCKET_INPUT_EXTRA = "socket_input" ;
@@ -48,7 +57,7 @@ public interface ResultWriter {
4857 }
4958
5059 /**
51- * Possible subclass of {@link ResultWriter} when input is to be read from stdin .
60+ * Possible subclass of {@link ResultWriter} when input is to be read from {@link #SOCKET_INPUT_EXTRA} .
5261 */
5362 public static abstract class WithInput implements ResultWriter {
5463 protected InputStream in ;
@@ -80,7 +89,7 @@ public final void writeResult(PrintWriter unused) throws Exception {
8089 }
8190
8291 /**
83- * Possible marker interface for a {@link ResultWriter} when input is to be read from stdin .
92+ * Possible marker interface for a {@link ResultWriter} when input is to be read from {@link #SOCKET_INPUT_EXTRA} .
8493 */
8594 public static abstract class WithStringInput extends WithInput {
8695 protected String inputString ;
@@ -179,6 +188,41 @@ public static void copyIntentExtras(Intent origIntent, Intent newIntent) {
179188
180189 }
181190
191+ /**
192+ * Get {@link LocalSocketAddress} for a socket address.
193+ *
194+ * If socket address starts with a path separator `/`, then a {@link Namespace#FILESYSTEM}
195+ * {@link LocalSocketAddress} is returned, otherwise an {@link Namespace#ABSTRACT}.
196+ *
197+ * The `termux-api-package` versions `<= 0.58.0` create a abstract namespace socket and higher
198+ * version create filesystem path socket.
199+ *
200+ * - https://man7.org/linux/man-pages/man7/unix.7.html
201+ */
202+ @ SuppressLint ("SdCardPath" )
203+ public static LocalSocketAddress getApiLocalSocketAddress (@ NonNull Context context ,
204+ @ NonNull String socketLabel , @ NonNull String socketAddress ) {
205+ if (socketAddress .startsWith ("/" )) {
206+ ApplicationInfo termuxApplicationInfo = PackageUtils .getApplicationInfoForPackage (context ,
207+ TermuxConstants .TERMUX_PACKAGE_NAME );
208+ if (termuxApplicationInfo == null ) {
209+ throw new RuntimeException ("Failed to get ApplicationInfo for the Termux app package: " +
210+ TermuxConstants .TERMUX_PACKAGE_NAME );
211+ }
212+
213+ List <String > termuxAppDataDirectories = Arrays .asList (termuxApplicationInfo .dataDir ,
214+ "/data/data/" + TermuxConstants .TERMUX_PACKAGE_NAME );
215+ if (!FileUtils .isPathInDirPaths (socketAddress , termuxAppDataDirectories , true )) {
216+ throw new RuntimeException ("The " + socketLabel + " socket address \" " + socketAddress + "\" " +
217+ " is not under Termux app data directories: " + termuxAppDataDirectories );
218+ }
219+
220+ return new LocalSocketAddress (socketAddress , Namespace .FILESYSTEM );
221+ } else {
222+ return new LocalSocketAddress (socketAddress , Namespace .ABSTRACT );
223+ }
224+ }
225+
182226 /**
183227 * Run in a separate thread, unless the context is an IntentService.
184228 */
@@ -192,11 +236,11 @@ public static void returnData(Object context, final Intent intent, final ResultW
192236 LocalSocket outputSocket = null ;
193237 try {
194238 outputSocket = new LocalSocket ();
195- String outputSocketAdress = intent .getStringExtra (SOCKET_OUTPUT_EXTRA );
196- if (outputSocketAdress == null || outputSocketAdress .isEmpty ())
239+ String outputSocketAddress = intent .getStringExtra (SOCKET_OUTPUT_EXTRA );
240+ if (outputSocketAddress == null || outputSocketAddress .isEmpty ())
197241 throw new IOException ("Missing '" + SOCKET_OUTPUT_EXTRA + "' extra" );
198- Logger .logDebug (LOG_TAG , "Connecting to output socket \" " + outputSocketAdress + "\" " );
199- outputSocket .connect (new LocalSocketAddress ( outputSocketAdress ));
242+ Logger .logDebug (LOG_TAG , "Connecting to output socket \" " + outputSocketAddress + "\" " );
243+ outputSocket .connect (getApiLocalSocketAddress ( ResultReturner . context , "output" , outputSocketAddress ));
200244 writer = new PrintWriter (outputSocket .getOutputStream ());
201245
202246 if (resultWriter != null ) {
@@ -209,10 +253,10 @@ public static void returnData(Object context, final Intent intent, final ResultW
209253 }
210254 if (resultWriter instanceof WithInput ) {
211255 try (LocalSocket inputSocket = new LocalSocket ()) {
212- String inputSocketAdress = intent .getStringExtra (SOCKET_INPUT_EXTRA );
213- if (inputSocketAdress == null || inputSocketAdress .isEmpty ())
256+ String inputSocketAddress = intent .getStringExtra (SOCKET_INPUT_EXTRA );
257+ if (inputSocketAddress == null || inputSocketAddress .isEmpty ())
214258 throw new IOException ("Missing '" + SOCKET_INPUT_EXTRA + "' extra" );
215- inputSocket .connect (new LocalSocketAddress ( inputSocketAdress ));
259+ inputSocket .connect (getApiLocalSocketAddress ( ResultReturner . context , "input" , inputSocketAddress ));
216260 ((WithInput ) resultWriter ).setInput (inputSocket .getInputStream ());
217261 resultWriter .writeResult (writer );
218262 }
0 commit comments