Added: Add support for plugin apps to set TERMUX_APP_PACKAGE_VARIANT and TERMUX_APP_PACKAGE_MANAGER from Termux app APK BuildConfig.TERMUX_PACKAGE_VARIANT

This commit is contained in:
agnostic-apollo
2022-06-01 00:09:10 +05:00
parent 980bf8f0ae
commit 46cfea09ec
4 changed files with 110 additions and 2 deletions

View File

@@ -77,6 +77,8 @@ public class ReflectionUtils {
/**
* Get a value for a {@link Field} of an object for the specified class.
*
* Trying to access {@code null} fields will result in {@link NoSuchFieldException}.
*
* @param clazz The {@link Class} to which the object belongs to.
* @param fieldName The name of the {@link Field}.
* @param object The {@link Object} instance from which to get the field value.

View File

@@ -1,20 +1,29 @@
package com.termux.shared.termux;
import android.content.Context;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.termux.shared.logger.Logger;
import com.termux.shared.termux.TermuxConstants.TERMUX_APP;
public class TermuxBootstrap {
private static final String LOG_TAG = "TermuxBootstrap";
/** The field name used by Termux app to store package variant in
* {@link TERMUX_APP#BUILD_CONFIG_CLASS_NAME} class. */
public static final String BUILD_CONFIG_FIELD_TERMUX_PACKAGE_VARIANT = "TERMUX_PACKAGE_VARIANT";
/** The {@link PackageManager} for the bootstrap in the app APK added in app/build.gradle. */
public static PackageManager TERMUX_APP_PACKAGE_MANAGER;
/** The {@link PackageVariant} for the bootstrap in the app APK added in app/build.gradle. */
public static PackageVariant TERMUX_APP_PACKAGE_VARIANT;
/** Set name as app wide night mode value. */
/** Set {@link #TERMUX_APP_PACKAGE_VARIANT} and {@link #TERMUX_APP_PACKAGE_MANAGER} from {@code packageVariantName} passed. */
public static void setTermuxPackageManagerAndVariant(@Nullable String packageVariantName) {
TERMUX_APP_PACKAGE_VARIANT = PackageVariant.variantOf(packageVariantName);
if (TERMUX_APP_PACKAGE_VARIANT == null) {
@@ -34,6 +43,42 @@ public class TermuxBootstrap {
Logger.logVerbose(LOG_TAG, "Set TERMUX_APP_PACKAGE_MANAGER to \"" + TERMUX_APP_PACKAGE_MANAGER + "\"");
}
/**
* Set {@link #TERMUX_APP_PACKAGE_VARIANT} and {@link #TERMUX_APP_PACKAGE_MANAGER} with the
* {@link #BUILD_CONFIG_FIELD_TERMUX_PACKAGE_VARIANT} field value from the
* {@link TERMUX_APP#BUILD_CONFIG_CLASS_NAME} class of the Termux app APK installed on the device.
* This can only be used by apps that share `sharedUserId` with the Termux app and can be used
* by plugin apps.
*
* @param currentPackageContext The context of current package.
*/
public static void setTermuxPackageManagerAndVariantFromTermuxApp(@NonNull Context currentPackageContext) {
String packageVariantName = getTermuxAppBuildConfigPackageVariantFromTermuxApp(currentPackageContext);
if (packageVariantName != null) {
TermuxBootstrap.setTermuxPackageManagerAndVariant(packageVariantName);
} else {
Logger.logError(LOG_TAG, "Failed to set TERMUX_APP_PACKAGE_VARIANT and TERMUX_APP_PACKAGE_MANAGER from the termux app");
}
}
/**
* Get {@link #BUILD_CONFIG_FIELD_TERMUX_PACKAGE_VARIANT} field value from the
* {@link TERMUX_APP#BUILD_CONFIG_CLASS_NAME} class of the Termux app APK installed on the device.
* This can only be used by apps that share `sharedUserId` with the Termux app.
*
* @param currentPackageContext The context of current package.
* @return Returns the field value, otherwise {@code null} if an exception was raised or failed
* to get termux app package context.
*/
public static String getTermuxAppBuildConfigPackageVariantFromTermuxApp(@NonNull Context currentPackageContext) {
try {
return (String) TermuxUtils.getTermuxAppAPKBuildConfigClassField(currentPackageContext, BUILD_CONFIG_FIELD_TERMUX_PACKAGE_VARIANT);
} catch (Exception e) {
Logger.logStackTraceWithMessage(LOG_TAG, "Failed to get \"" + BUILD_CONFIG_FIELD_TERMUX_PACKAGE_VARIANT + "\" value from \"" + TERMUX_APP.BUILD_CONFIG_CLASS_NAME + "\" class", e);
return null;
}
}
/** Is {@link PackageManager#APT} set as {@link #TERMUX_APP_PACKAGE_MANAGER}. */

View File

@@ -11,7 +11,7 @@ import java.util.Formatter;
import java.util.List;
/*
* Version: v0.44.0
* Version: v0.45.0
* SPDX-License-Identifier: MIT
*
* Changelog
@@ -248,6 +248,9 @@ import java.util.List;
*
* - 0.44.0 (2022-05-29)
* - Changed `TERMUX_APP.APPS_DIR_PATH` basename from `termux-app` to `com.termux`.
*
* - 0.45.0 (2022-06-01)
* - Added `TERMUX_APP.BUILD_CONFIG_CLASS_NAME`.
*/
/**
@@ -904,6 +907,9 @@ public final class TermuxConstants {
/** termux-am socket file path */
public static final String TERMUX_AM_SOCKET_FILE_PATH = APPS_DIR_PATH + "/termux-am/am.sock"; // Default: "/data/data/com.termux/files/apps/com.termux/termux-am/am.sock"
/** Termux app BuildConfig class name */
public static final String BUILD_CONFIG_CLASS_NAME = TERMUX_PACKAGE_NAME + ".BuildConfig"; // Default: "com.termux.BuildConfig"
/** Termux app core activity name. */
public static final String TERMUX_ACTIVITY_NAME = TERMUX_PACKAGE_NAME + ".app.TermuxActivity"; // Default: "com.termux.app.TermuxActivity"

View File

@@ -14,6 +14,7 @@ import com.termux.shared.R;
import com.termux.shared.android.AndroidUtils;
import com.termux.shared.data.DataUtils;
import com.termux.shared.file.FileUtils;
import com.termux.shared.reflection.ReflectionUtils;
import com.termux.shared.shell.command.runner.app.AppShell;
import com.termux.shared.termux.file.TermuxFileUtils;
import com.termux.shared.logger.Logger;
@@ -21,6 +22,7 @@ import com.termux.shared.markdown.MarkdownUtils;
import com.termux.shared.shell.command.ExecutionCommand;
import com.termux.shared.errors.Error;
import com.termux.shared.android.PackageUtils;
import com.termux.shared.termux.TermuxConstants.TERMUX_APP;
import com.termux.shared.termux.shell.TermuxShellEnvironmentClient;
import org.apache.commons.io.IOUtils;
@@ -218,6 +220,59 @@ public class TermuxUtils {
/**
* Get a field value from the {@link TERMUX_APP#BUILD_CONFIG_CLASS_NAME} class of the Termux app
* APK installed on the device.
* This can only be used by apps that share `sharedUserId` with the Termux app.
*
* This is a wrapper for {@link #getTermuxAppAPKClassField(Context, String, String)}.
*
* @param currentPackageContext The context of current package.
* @param fieldName The name of the field to get.
* @return Returns the field value, otherwise {@code null} if an exception was raised or failed
* to get termux app package context.
*/
public static Object getTermuxAppAPKBuildConfigClassField(@NonNull Context currentPackageContext,
@NonNull String fieldName) {
return getTermuxAppAPKClassField(currentPackageContext, TERMUX_APP.BUILD_CONFIG_CLASS_NAME, fieldName);
}
/**
* Get a field value from a class of the Termux app APK installed on the device.
* This can only be used by apps that share `sharedUserId` with the Termux app.
*
* This is done by getting first getting termux app package context and then getting in class
* loader (instead of current app's) that contains termux app class info, and then using that to
* load the required class and then getting required field from it.
*
* Note that the value returned is from the APK file and not the current value loaded in Termux
* app process, so only default values will be returned.
*
* Trying to access {@code null} fields will result in {@link NoSuchFieldException}.
*
* @param currentPackageContext The context of current package.
* @param clazzName The name of the class from which to get the field.
* @param fieldName The name of the field to get.
* @return Returns the field value, otherwise {@code null} if an exception was raised or failed
* to get termux app package context.
*/
public static Object getTermuxAppAPKClassField(@NonNull Context currentPackageContext,
@NonNull String clazzName, @NonNull String fieldName) {
try {
Context termuxPackageContext = TermuxUtils.getTermuxPackageContextWithCode(currentPackageContext);
if (termuxPackageContext == null)
return null;
Class<?> clazz = termuxPackageContext.getClassLoader().loadClass(clazzName);
return ReflectionUtils.invokeField(clazz, fieldName, null).value;
} catch (Exception e) {
Logger.logStackTraceWithMessage(LOG_TAG, "Failed to get \"" + fieldName + "\" value from \"" + clazzName + "\" class", e);
return null;
}
}
/**
* Send the {@link TermuxConstants#BROADCAST_TERMUX_OPENED} broadcast to notify apps that Termux
* app has been opened.