Skip to content

Commit

Permalink
fixing termux-x11-preference for Android 14+
Browse files Browse the repository at this point in the history
  • Loading branch information
twaik committed Jan 12, 2025
1 parent 1b04e30 commit efb2d97
Show file tree
Hide file tree
Showing 5 changed files with 116 additions and 24 deletions.
5 changes: 5 additions & 0 deletions app/src/main/aidl/com/termux/x11/IRemoteCmdImterface.aidl
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.termux.x11;

interface IRemoteCmdImterface {
void exit(int code, String output);
}
12 changes: 9 additions & 3 deletions app/src/main/java/com/termux/x11/CmdEntryPoint.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import android.content.IIntentReceiver;
import android.content.IIntentSender;
import android.content.Intent;
import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
Expand All @@ -29,8 +30,9 @@
@Keep @SuppressLint({"StaticFieldLeak", "UnsafeDynamicallyLoadedCode"})
public class CmdEntryPoint extends ICmdEntryInterface.Stub {
public static final String ACTION_START = "com.termux.x11.CmdEntryPoint.ACTION_START";
private static final Handler handler;
static final Handler handler;
public static Context ctx;
private final Intent intent = createIntent();

/**
* Command-line entry point.
Expand All @@ -52,7 +54,7 @@ public static void main(String[] args) {
}

@SuppressLint({"WrongConstant", "PrivateApi"})
void sendBroadcast() {
private Intent createIntent() {
String targetPackage = getenv("TERMUX_X11_OVERRIDE_PACKAGE");
if (targetPackage == null)
targetPackage = "com.termux.x11";
Expand All @@ -68,6 +70,10 @@ void sendBroadcast() {
if (getuid() == 0 || getuid() == 2000)
intent.setFlags(0x00400000 /* FLAG_RECEIVER_FROM_SHELL */);

return intent;
}

static void sendBroadcast(Intent intent) {
try {
ctx.sendBroadcast(intent);
} catch (Exception e) {
Expand Down Expand Up @@ -118,7 +124,7 @@ void sendBroadcast() {
// In this case opened port works like a lock file.
private void sendBroadcastDelayed() {
if (!connected())
sendBroadcast();
sendBroadcast(intent);

handler.postDelayed(this::sendBroadcastDelayed, 1000);
}
Expand Down
112 changes: 92 additions & 20 deletions app/src/main/java/com/termux/x11/LoriePreferences.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import static android.content.pm.PackageManager.PERMISSION_DENIED;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.os.Build.VERSION.SDK_INT;
import static android.system.Os.getuid;

import android.annotation.SuppressLint;
import android.content.BroadcastReceiver;
Expand All @@ -22,6 +23,7 @@
import android.os.Build;
import android.os.Bundle;

import androidx.annotation.Keep;
import androidx.annotation.NonNull;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
Expand All @@ -31,6 +33,7 @@
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.RemoteException;
import android.preference.PreferenceManager;

import androidx.annotation.Nullable;
Expand Down Expand Up @@ -68,6 +71,7 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Objects;
import java.util.Scanner;
import java.util.Set;
import java.util.function.Consumer;
import java.util.regex.PatternSyntaxException;
Expand Down Expand Up @@ -493,8 +497,12 @@ public IBinder peekService(Context myContext, Intent service) {
@SuppressLint("ApplySharedPref")
@Override
public void onReceive(Context context, Intent intent) {
Bundle bundle = intent != null ? intent.getBundleExtra(null) : null;
IBinder ibinder = bundle != null ? bundle.getBinder(null) : null;
IRemoteCmdImterface remote = ibinder != null ? IRemoteCmdImterface.Stub.asInterface(ibinder) : null;

try {
if (intent.getExtras() != null) {
if (intent != null && intent.getExtras() != null) {
Prefs p = (MainActivity.getInstance() != null) ? new Prefs(MainActivity.getInstance()) : (prefs != null ? prefs : new Prefs(context));
if (intent.getStringExtra("list") != null) {
String result = "";
Expand All @@ -516,14 +524,14 @@ else if (pref.type == String[].class) {
}
}

setResultCode(2);
setResultData(result);

sendResponse(remote, 0, 2, result.substring(0, result.length() - 1));
return;
}

SharedPreferences.Editor edit = p.get().edit();
for (String key : intent.getExtras().keySet()) {
if (key == null)
continue;
String newValue = intent.getStringExtra(key);
if (newValue == null)
continue;
Expand All @@ -535,8 +543,7 @@ else if (pref.type == String[].class) {
Integer.parseInt(resolution[0]);
Integer.parseInt(resolution[1]);
} catch (NumberFormatException | PatternSyntaxException ignored) {
setResultCode(1);
setResultData("displayResolutionCustom: Wrong resolution format.");
sendResponse(remote, 1, 1, "displayResolutionCustom: Wrong resolution format.");
return;
}

Expand All @@ -547,8 +554,7 @@ else if (pref.type == String[].class) {
if (!"true".equals(newValue))
KeyInterceptor.shutdown(false);
else if (context.checkSelfPermission(WRITE_SECURE_SETTINGS) != PERMISSION_GRANTED) {
setResultCode(1);
setResultData("Permission denied.\n" +
sendResponse(remote, 1, 1, "Permission denied.\n" +
"Android requires WRITE_SECURE_SETTINGS permission to change `enableAccessibilityServiceAutomatically` setting.\n" +
"Please, launch this command using ADB:\n" +
"adb shell pm grant com.termux.x11 android.permission.WRITE_SECURE_SETTINGS");
Expand All @@ -572,8 +578,7 @@ else if (context.checkSelfPermission(WRITE_SECURE_SETTINGS) != PERMISSION_GRANTE
try {
edit.putInt(key, Integer.parseInt(newValue));
} catch (NumberFormatException | PatternSyntaxException exception) {
setResultCode(4);
setResultData(key + ": failed to parse integer: " + exception);
sendResponse(remote, 1, 4, key + ": failed to parse integer: " + exception);
return;
}
} else if (pref != null && pref.type == String[].class) {
Expand All @@ -590,12 +595,10 @@ else if (context.checkSelfPermission(WRITE_SECURE_SETTINGS) != PERMISSION_GRANTE
break;
}

setResultCode(1);
setResultData(key + ": can not be set to \"" + newValue + "\", possible options are " + Arrays.toString(entries) + (_p.entries != _p.values ? " or " + Arrays.toString(values) : ""));
sendResponse(remote, 1, 1, key + ": can not be set to \"" + newValue + "\", possible options are " + Arrays.toString(entries) + (_p.entries != _p.values ? " or " + Arrays.toString(values) : ""));
return;
} else {
setResultCode(4);
setResultData(key + ": unrecognised option");
sendResponse(remote, 1, 4, key + ": unrecognised option");
return;
}
}
Expand All @@ -610,19 +613,88 @@ else if (context.checkSelfPermission(WRITE_SECURE_SETTINGS) != PERMISSION_GRANTE
edit.commit();
}

setResultCode(2);
setResultData("Done");
sendResponse(remote, 0, 2, "Done");
} catch (Exception e) {
setResultCode(4);
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
e.printStackTrace(pw);
setResultData(sw.toString());
sendResponse(remote, 1, 4, sw.toString());
}
}

void sendResponse(IRemoteCmdImterface remote, int status, int oldStatus, String text) {
if (remote != null) {
try {
remote.exit(status, text);
} catch (RemoteException ex) {
Log.e("LoriePreferences", "Failed to send response to commandline proxy", ex);
}
} else if (isOrderedBroadcast()) {
setResultCode(oldStatus);
setResultData(text);
}
}

// For changing preferences from commandline
private static final IBinder iface = new IRemoteCmdImterface.Stub() {
@Override
public void exit(int code, String output) {
System.out.println(output);
CmdEntryPoint.handler.post(() -> System.exit(code));
}
};

private static void help() {
System.err.print("termux-x11-preference [list] {key:value} [{key2:value2}]...");
System.exit(0);
}

@Keep
@SuppressLint("WrongConstant")
public static void main(String[] args) {
android.util.Log.i("LoriePreferences$Receiver", "commit " + BuildConfig.COMMIT);
Bundle bundle = new Bundle();
bundle.putBinder(null, iface);

Intent i = new Intent("com.termux.x11.CHANGE_PREFERENCE");
i.setPackage("com.termux.x11");
i.putExtra(null, bundle);
if (getuid() == 0 || getuid() == 2000)
i.setFlags(0x00400000 /* FLAG_RECEIVER_FROM_SHELL */);

if (System.console() == null && System.in != null) {
Scanner scanner = new Scanner(System.in);
String line;
String[] v;
while (scanner.hasNextLine()) {
line = scanner.nextLine();
if (!line.contains("="))
help();

v = line.split("=");
i.putExtra(v[0], v[1]);
}
}

for (String a: args) {
if ("list".equals(a)) {
i.putExtra("list", "");
} else if (a != null && a.contains(":")) {
String[] v = a.split(":");
i.putExtra(v[0], v[1]);
} else
help();
}

CmdEntryPoint.handler.post(() -> CmdEntryPoint.sendBroadcast(i));
CmdEntryPoint.handler.postDelayed(() -> {
System.err.println("Failed to obtain response from app.");
System.exit(1);
}, 5000);
Looper.loop();
}
}

static Handler handler = new Handler(Looper.getMainLooper());
static Handler handler = Looper.getMainLooper() != null ? new Handler(Looper.getMainLooper()) : null;

public void onClick(View view) {
showFragment(new LoriePreferenceFragment("ekbar"));
Expand Down
4 changes: 3 additions & 1 deletion shell-loader/src/main/java/com/termux/x11/Loader.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ public class Loader {
* @param args The command-line arguments
*/
public static void main(String[] args) {
String cls = System.getenv("TERMUX_X11_LOADER_OVERRIDE_CMDENTRYPOINT_CLASS");
cls = cls != null ? cls : BuildConfig.CLASS_ID;
try {
android.content.pm.PackageInfo targetInfo = (android.os.Build.VERSION.SDK_INT <= 32) ?
android.app.ActivityThread.getPackageManager().getPackageInfo(BuildConfig.APPLICATION_ID, android.content.pm.PackageManager.GET_SIGNATURES, 0) :
Expand All @@ -22,7 +24,7 @@ public static void main(String[] args) {
assert targetInfo.signatures.length == 1 && BuildConfig.SIGNATURE == targetInfo.signatures[0].hashCode() : BuildConfig.packageSignatureMismatchErrorText;

android.util.Log.i(BuildConfig.logTag, "loading " + targetInfo.applicationInfo.sourceDir + "::" + BuildConfig.CLASS_ID + "::main of " + BuildConfig.APPLICATION_ID + " application (commit " + BuildConfig.COMMIT + ")");
Class<?> targetClass = Class.forName(BuildConfig.CLASS_ID, true,
Class<?> targetClass = Class.forName(cls, true,
new dalvik.system.PathClassLoader(targetInfo.applicationInfo.sourceDir, null, ClassLoader.getSystemClassLoader()));
targetClass.getMethod("main", String[].class).invoke(null, (Object) args);
} catch (AssertionError e) {
Expand Down
7 changes: 7 additions & 0 deletions termux-x11-preference
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
#!/data/data/com.termux/files/usr/bin/bash
if [ "$(getprop ro.build.version.sdk)" -ge "34" ]; then
unset LD_LIBRARY_PATH LD_PRELOAD
export CLASSPATH=/data/data/com.termux/files/usr/libexec/termux-x11/loader.apk
export TERMUX_X11_LOADER_OVERRIDE_CMDENTRYPOINT_CLASS=com.termux.x11.LoriePreferences\$Receiver
exec /system/bin/app_process -Xnoimage-dex2oat / com.termux.x11.Loader "$@"
fi

COMMAND=("am" "broadcast" "-a" "com.termux.x11.CHANGE_PREFERENCE" "-p" "com.termux.x11")
help() {
echo "$0 [list] {key:value} [{key2:value2}]..."
Expand Down

0 comments on commit efb2d97

Please sign in to comment.