From 46cd5143431276f9e5f6cb8718ec3dc799e2b977 Mon Sep 17 00:00:00 2001 From: agnostic-apollo Date: Fri, 28 Mar 2025 13:12:58 +0500 Subject: [PATCH] Fixed: Set `minSdkVersion` and `maxSdkVersion` depending on apk bootstrap variant and abort bootstrap installation if trying to install wrong variant - `apt-android-7` variant will set `minSdkVersion=24` (Android `7.0`) and bootstrap installation will fail if installing on Android `< 7`. Normally, APK installation will fail with `INSTALL_FAILED_OLDER_SDK` if trying to install on an old version, or if APK is manually installed in `/data/app`, it should fail to run and app will be disabled/removed on reboot. - `apt-android-5` variant will set `minSdkVersion=21` (Android `5.0`) and `maxSdkVersion=23` (Android `6.0`) and bootstrap installation will fail if installing on Android `>= 7`. Android does not care for `maxSdkVersion` value and will still allow installation on higher Android versions as the OS provides backward compatibility for apps, but Termux packages do not provide that, so must not be installed on higher Android versions. This should solve the issue for `0.119.0*` releases showing on F-Droid for Android `5`/`6` users as previously the `apt-android-7` variant was still using `minSdkVersion=21`. Android `5`/`6` releases with `apt-android-5` variant are only to be provided from GitHub. --- app/build.gradle | 17 ++++++- .../java/com/termux/app/TermuxInstaller.java | 44 +++++++++++++++++++ app/src/main/res/values/strings.xml | 10 ++++- 3 files changed, 68 insertions(+), 3 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 1c6045b4..64e96bfc 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -10,6 +10,13 @@ ext { // by replacing $PREFIX since app code is dependant on the variant used to build the APK. // Currently supported values are: [ "apt-android-7" "apt-android-5" ] packageVariant = System.getenv("TERMUX_PACKAGE_VARIANT") ?: "apt-android-7" // Default: "apt-android-7" + bootstrapMinSdk = packageVariant == "apt-android-5" ? 21 : 24 + bootstrapMinRelease = packageVariant == "apt-android-5" ? "5.0" : "7.0" + bootstrapMaxSdk = packageVariant == "apt-android-5" ? 23 : null + bootstrapMaxRelease = packageVariant == "apt-android-5" ? "6.0" : null + + buildMinSdk = bootstrapMinSdk + buildTargetSdk = project.properties.targetSdkVersion.toInteger() } android { @@ -39,14 +46,20 @@ android { defaultConfig { applicationId "com.termux" - minSdkVersion project.properties.minSdkVersion.toInteger() - targetSdkVersion project.properties.targetSdkVersion.toInteger() + minSdk buildMinSdk + targetSdk buildTargetSdk versionCode 1020 versionName "0.119.0-beta.1" if (appVersionName) versionName = appVersionName validateVersionName(versionName) + buildConfigField "Integer", "TERMUX_APP__BOOTSTRAP_MIN_SDK", project.ext.bootstrapMinSdk.toString() + buildConfigField "String", "TERMUX_APP__BOOTSTRAP_MIN_RELEASE", + project.ext.bootstrapMinRelease ? "\"" + project.ext.bootstrapMinRelease + "\"" : "null" + buildConfigField "Integer", "TERMUX_APP__BOOTSTRAP_MAX_SDK", project.ext.bootstrapMaxSdk.toString() + buildConfigField "String", "TERMUX_APP__BOOTSTRAP_MAX_RELEASE", + project.ext.bootstrapMaxRelease ? "\"" + project.ext.bootstrapMaxRelease + "\"" : "null" buildConfigField "String", "TERMUX_PACKAGE_VARIANT", "\"" + project.ext.packageVariant + "\"" // Used by TermuxApplication class manifestPlaceholders.TERMUX_PACKAGE_NAME = "com.termux" diff --git a/app/src/main/java/com/termux/app/TermuxInstaller.java b/app/src/main/java/com/termux/app/TermuxInstaller.java index 403ab208..690fc482 100644 --- a/app/src/main/java/com/termux/app/TermuxInstaller.java +++ b/app/src/main/java/com/termux/app/TermuxInstaller.java @@ -10,10 +10,12 @@ import android.system.Os; import android.util.Pair; import android.view.WindowManager; +import com.termux.BuildConfig; import com.termux.R; import com.termux.shared.file.FileUtils; import com.termux.shared.shell.command.ExecutionCommand; import com.termux.shared.shell.command.runner.app.AppShell; +import com.termux.shared.termux.TermuxBootstrap; import com.termux.shared.termux.crash.TermuxCrashUtils; import com.termux.shared.termux.file.TermuxFileUtils; import com.termux.shared.interact.MessageDialogUtils; @@ -104,6 +106,12 @@ final class TermuxInstaller { return; } + if (!checkIfMinOrMaxSdkVersionIsIncompatible(activity, + BuildConfig.TERMUX_APP__BOOTSTRAP_MIN_SDK, BuildConfig.TERMUX_APP__BOOTSTRAP_MIN_RELEASE, + BuildConfig.TERMUX_APP__BOOTSTRAP_MAX_SDK, BuildConfig.TERMUX_APP__BOOTSTRAP_MAX_RELEASE)) { + return; + } + // If prefix directory exists, even if its a symlink to a valid directory and symlink is not broken/dangling if (FileUtils.directoryFileExists(TERMUX_PREFIX_DIR_PATH, true)) { if (TermuxFileUtils.isTermuxPrefixDirectoryEmpty()) { @@ -271,6 +279,42 @@ final class TermuxInstaller { }.start(); } + public static boolean checkIfMinOrMaxSdkVersionIsIncompatible(Activity activity, + Integer minSdk, String minRelease, + Integer maxSdk, String maxRelease) { + if (minSdk != null && Build.VERSION.SDK_INT < minSdk) { + String bootstrapErrorMessage = activity.getString(R.string.bootstrap_error_apk_bootstrap_variant_min_sdk_incompatible, + MarkdownUtils.getMarkdownCodeForString(TermuxBootstrap.TERMUX_APP_PACKAGE_VARIANT.getName(), false), + MarkdownUtils.getMarkdownCodeForString(Build.VERSION.RELEASE, false), + Build.VERSION.SDK_INT, + MarkdownUtils.getMarkdownCodeForString(minRelease, false), + minSdk); + Logger.logError(LOG_TAG, bootstrapErrorMessage); + sendBootstrapCrashReportNotification(activity, bootstrapErrorMessage); + MessageDialogUtils.exitAppWithErrorMessage(activity, + activity.getString(R.string.bootstrap_error_title), + bootstrapErrorMessage); + return false; + } + + if (maxSdk != null && Build.VERSION.SDK_INT > maxSdk) { + String bootstrapErrorMessage = activity.getString(R.string.bootstrap_error_apk_bootstrap_variant_max_sdk_incompatible, + MarkdownUtils.getMarkdownCodeForString(TermuxBootstrap.TERMUX_APP_PACKAGE_VARIANT.getName(), false), + MarkdownUtils.getMarkdownCodeForString(Build.VERSION.RELEASE, false), + Build.VERSION.SDK_INT, + MarkdownUtils.getMarkdownCodeForString(maxRelease, false), + maxSdk); + Logger.logError(LOG_TAG, bootstrapErrorMessage); + sendBootstrapCrashReportNotification(activity, bootstrapErrorMessage); + MessageDialogUtils.exitAppWithErrorMessage(activity, + activity.getString(R.string.bootstrap_error_title), + bootstrapErrorMessage); + return false; + } + + return true; + } + public static void showBootstrapErrorDialog(Activity activity, Runnable whenDone, String message) { Logger.logErrorExtended(LOG_TAG, "Bootstrap Error:\n" + message); diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index cbd2992b..8c9cd7ae 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -27,10 +27,18 @@ Installing bootstrap packages… - Unable to install bootstrap + &TERMUX_APP_NAME; Bootstrap Error &TERMUX_APP_NAME; was unable to install the bootstrap packages. Abort Try again + The APK bootstrap variant %1$s + of currently installed &TERMUX_APP_NAME; app is not compatible with the Android version %2$s + (sdk `%3$d`) of the device and it requires minimum Android version %4$s (sdk `%5$d`). + \n\nUninstall the &TERMUX_APP_NAME; app and reinstall the correct APK build variant. + The APK bootstrap variant %1$s + of currently installed &TERMUX_APP_NAME; app is not compatible with the Android version %2$s + (sdk `%3$d`) of the device and it requires maximum Android version %4$s (sdk `%5$d`). + \n\nUninstall the &TERMUX_APP_NAME; app and reinstall the correct APK build variant. &TERMUX_APP_NAME; can only be run as the primary user. \nBootstrap binaries compiled for &TERMUX_APP_NAME; have hardcoded $PREFIX path and cannot be installed under any path other than:\n%1$s.