mirror of
https://github.com/fankes/termux-app.git
synced 2025-09-07 11:09:49 +08:00
Added: Write termux shell environment to /data/data/com.termux/files/usr/etc/termux/termux.env
on app startup and package changes
The `termux.env` can be sourced by shells to set termux environment normally exported. This can be useful for users starting termux shells with `adb` `run-as` or `root`. The file will not contain `SHELL_CMD__` variables since those are shell command specific. The items in the `termux.env` file have the format `export name="value"`. The `"`\$` characters will be escaped with `a backslash `\`, like `\"` if characters are for literal value. Note that if `$` is escaped and if its part of variable, then variable expansion will not happen if `.env` file is sourced. The `\` at the end of a value line means line continuation. Value can contain newline characters. The `termux.env` file should be sourceable by `POSIX` compliant shells like `bash`, `zsh`, `sh`, android's `mksh`, etc. Other shells with require manual parsing of the file to export variables. Related discussion #2565
This commit is contained in:
@@ -12,6 +12,7 @@ import com.termux.shared.termux.crash.TermuxCrashUtils;
|
||||
import com.termux.shared.termux.file.TermuxFileUtils;
|
||||
import com.termux.shared.termux.settings.preferences.TermuxAppSharedPreferences;
|
||||
import com.termux.shared.termux.settings.properties.TermuxAppSharedProperties;
|
||||
import com.termux.shared.termux.shell.command.environment.TermuxShellEnvironment;
|
||||
import com.termux.shared.termux.shell.am.TermuxAmSocketServer;
|
||||
import com.termux.shared.termux.shell.TermuxShellManager;
|
||||
import com.termux.shared.termux.theme.TermuxThemeUtils;
|
||||
@@ -48,9 +49,8 @@ public class TermuxApplication extends Application {
|
||||
// Check and create termux files directory. If failed to access it like in case of secondary
|
||||
// user or external sd card installation, then don't run files directory related code
|
||||
Error error = TermuxFileUtils.isTermuxFilesDirectoryAccessible(this, true, true);
|
||||
if (error != null) {
|
||||
Logger.logErrorExtended(LOG_TAG, "Termux files directory is not accessible\n" + error);
|
||||
} else {
|
||||
boolean isTermuxFilesDirectoryAccessible = error == null;
|
||||
if (isTermuxFilesDirectoryAccessible) {
|
||||
Logger.logInfo(LOG_TAG, "Termux files directory is accessible");
|
||||
|
||||
error = TermuxFileUtils.isAppsTermuxAppDirectoryAccessible(true, true);
|
||||
@@ -59,10 +59,17 @@ public class TermuxApplication extends Application {
|
||||
return;
|
||||
}
|
||||
|
||||
// Setup termux-am-socket server
|
||||
TermuxAmSocketServer.setupTermuxAmSocketServer(context);
|
||||
} else {
|
||||
Logger.logErrorExtended(LOG_TAG, "Termux files directory is not accessible\n" + error);
|
||||
}
|
||||
|
||||
// Init TermuxShellEnvironment constants and caches after everything has been setup including termux-am-socket server
|
||||
TermuxShellEnvironment.init(this);
|
||||
|
||||
if (isTermuxFilesDirectoryAccessible) {
|
||||
TermuxShellEnvironment.writeEnvironmentToFile(this);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -19,6 +19,7 @@ import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.termux.R;
|
||||
import com.termux.app.event.SystemEventReceiver;
|
||||
import com.termux.app.terminal.TermuxTerminalSessionClient;
|
||||
import com.termux.shared.termux.plugins.TermuxPluginUtils;
|
||||
import com.termux.shared.data.IntentUtils;
|
||||
@@ -116,6 +117,8 @@ public final class TermuxService extends Service implements AppShell.AppShellCli
|
||||
mShellManager = TermuxShellManager.getShellManager();
|
||||
|
||||
runStartForeground();
|
||||
|
||||
SystemEventReceiver.registerPackageUpdateEvents(this);
|
||||
}
|
||||
|
||||
@SuppressLint("Wakelock")
|
||||
@@ -172,6 +175,9 @@ public final class TermuxService extends Service implements AppShell.AppShellCli
|
||||
killAllTermuxExecutionCommands();
|
||||
|
||||
TermuxShellManager.onAppExit(this);
|
||||
|
||||
SystemEventReceiver.unregisterPackageUpdateEvents(this);
|
||||
|
||||
runStopForeground();
|
||||
}
|
||||
|
||||
|
@@ -2,12 +2,18 @@ package com.termux.app.event;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.net.Uri;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.termux.shared.data.IntentUtils;
|
||||
import com.termux.shared.logger.Logger;
|
||||
import com.termux.shared.termux.TermuxUtils;
|
||||
import com.termux.shared.termux.file.TermuxFileUtils;
|
||||
import com.termux.shared.termux.shell.command.environment.TermuxShellEnvironment;
|
||||
import com.termux.shared.termux.shell.TermuxShellManager;
|
||||
|
||||
public class SystemEventReceiver extends BroadcastReceiver {
|
||||
@@ -35,6 +41,11 @@ public class SystemEventReceiver extends BroadcastReceiver {
|
||||
case Intent.ACTION_BOOT_COMPLETED:
|
||||
onActionBootCompleted(context, intent);
|
||||
break;
|
||||
case Intent.ACTION_PACKAGE_ADDED:
|
||||
case Intent.ACTION_PACKAGE_REMOVED:
|
||||
case Intent.ACTION_PACKAGE_REPLACED:
|
||||
onActionPackageUpdated(context, intent);
|
||||
break;
|
||||
default:
|
||||
Logger.logError(LOG_TAG, "Invalid action \"" + action + "\" passed to " + LOG_TAG);
|
||||
}
|
||||
@@ -44,4 +55,37 @@ public class SystemEventReceiver extends BroadcastReceiver {
|
||||
TermuxShellManager.onActionBootCompleted(context, intent);
|
||||
}
|
||||
|
||||
public synchronized void onActionPackageUpdated(@NonNull Context context, @NonNull Intent intent) {
|
||||
Uri data = intent.getData();
|
||||
if (data != null && TermuxUtils.isUriDataForTermuxPluginPackage(data)) {
|
||||
Logger.logDebug(LOG_TAG, intent.getAction().replaceAll("^android.intent.action.", "") +
|
||||
" event received for \"" + data.toString().replaceAll("^package:", "") + "\"");
|
||||
if (TermuxFileUtils.isTermuxFilesDirectoryAccessible(context, false, false) == null)
|
||||
TermuxShellEnvironment.writeEnvironmentToFile(context);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Register {@link SystemEventReceiver} to listen to {@link Intent#ACTION_PACKAGE_ADDED},
|
||||
* {@link Intent#ACTION_PACKAGE_REMOVED} and {@link Intent#ACTION_PACKAGE_REPLACED} broadcasts.
|
||||
* They must be registered dynamically and cannot be registered implicitly in
|
||||
* the AndroidManifest.xml due to Android 8+ restrictions.
|
||||
*
|
||||
* https://developer.android.com/guide/components/broadcast-exceptions
|
||||
*/
|
||||
public synchronized static void registerPackageUpdateEvents(@NonNull Context context) {
|
||||
IntentFilter intentFilter = new IntentFilter();
|
||||
intentFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
|
||||
intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
|
||||
intentFilter.addAction(Intent.ACTION_PACKAGE_REPLACED);
|
||||
intentFilter.addDataScheme("package");
|
||||
context.registerReceiver(getInstance(), intentFilter);
|
||||
}
|
||||
|
||||
public synchronized static void unregisterPackageUpdateEvents(@NonNull Context context) {
|
||||
context.unregisterReceiver(getInstance());
|
||||
}
|
||||
|
||||
}
|
||||
|
Reference in New Issue
Block a user