Buckets:
NaTo1000/termux-app-bucket / termux-shared /src /main /java /com /termux /shared /android /FeatureFlagUtils.java
| package com.termux.shared.android; | |
| import android.annotation.SuppressLint; | |
| import android.content.Context; | |
| import androidx.annotation.NonNull; | |
| import androidx.annotation.Nullable; | |
| import com.termux.shared.logger.Logger; | |
| import com.termux.shared.reflection.ReflectionUtils; | |
| import java.lang.reflect.Method; | |
| import java.util.Map; | |
| /** | |
| * Utils for Developer Options -> Feature Flags. The page won't show in user/production builds and | |
| * is only shown in userdebug builds. | |
| * https://cs.android.com/android/_/android/platform/frameworks/base/+/09dcdad5ebc159861920f090e07da60fac71ac0a:core/java/android/util/FeatureFlagUtils.java | |
| * https://cs.android.com/android/platform/superproject/+/android-12.0.0_r31:packages/apps/Settings/src/com/android/settings/development/featureflags/FeatureFlagsPreferenceController.java;l=42 | |
| * | |
| * The feature flags value can be modified in two ways. | |
| * | |
| * 1. sysprops with `setprop` command with root. Will be unset by default. | |
| * Set value: `setprop persist.sys.fflag.override.settings_enable_monitor_phantom_procs false` | |
| * Get value: `getprop persist.sys.fflag.override.settings_enable_monitor_phantom_procs` | |
| * Unset value: `setprop persist.sys.fflag.override.settings_enable_monitor_phantom_procs ""` | |
| * Running `setprop` command requires root and even adb `shell` user cannot modify the values | |
| * since selinux will not allow it by default. Some props like `settings_dynamic_system` can be | |
| * set since they are exempted for `shell` in sepolicy. | |
| * | |
| * init: Unable to set property 'persist.sys.fflag.override.settings_enable_monitor_phantom_procs' from uid:2000 gid:2000 pid:9576: SELinux permission check failed | |
| * [ 1034.877067] type=1107 audit(1644436809.637:34): uid=0 auid=4294967295 ses=4294967295 subj=u:r:init:s0 msg='avc: denied { set } for property=persist.sys.fflag.override.settings_enable_monitor_phantom_procs pid=9576 uid=2000 gid=2000 scontext=u:r:shell:s0 tcontext=u:object_r:system_prop:s0 tclass=property_service permissive=0' | |
| * | |
| * https://cs.android.com/android/platform/superproject/+/android-12.0.0_r4:system/sepolicy/private/property_contexts;l=71 | |
| * https://cs.android.com/android/platform/superproject/+/android-12.0.0_r4:system/sepolicy/private/shell.te;l=149 | |
| * | |
| * 2. settings global list with adb or root. Will be unset by default. This takes precedence over | |
| * sysprop value since `FeatureFlagUtils.isEnabled()` | |
| * checks its value first. Override precedence: Settings.Global -> sys.fflag.override.* -> static list. | |
| * Set value: `adb shell settings put global settings_enable_monitor_phantom_procs false` | |
| * Get value: adb shell settings get global settings_enable_monitor_phantom_procs` | |
| * Unset value: `adb shell settings delete global settings_enable_monitor_phantom_procs` | |
| * | |
| * https://cs.android.com/android/_/android/platform/frameworks/base/+/refs/tags/android-12.0.0_r31:core/java/android/util/FeatureFlagUtils.java;l=113 | |
| * | |
| * The feature flag values can be modified in user builds with settings global list, but since the | |
| * developer options feature flags page is not shown and considering that getprop values for features | |
| * will be unset by default and settings global list will not be set either and there is no shell API, | |
| * it will require an android app process to check if feature is supported on a device and what its | |
| * default value is with reflection after bypassing hidden api restrictions since {@link #FEATURE_FLAGS_CLASS} | |
| * is annotated as `@hide`. | |
| */ | |
| public class FeatureFlagUtils { | |
| public enum FeatureFlagValue { | |
| /** Unknown like due to exception raised while getting value. */ | |
| UNKNOWN("<unknown>"), | |
| /** Flag is unsupported on current android build. */ | |
| UNSUPPORTED("<unsupported>"), | |
| /** Flag is enabled. */ | |
| TRUE("true"), | |
| /** Flag is not enabled. */ | |
| FALSE("false"); | |
| private final String name; | |
| FeatureFlagValue(final String name) { | |
| this.name = name; | |
| } | |
| public String getName() { | |
| return name; | |
| } | |
| } | |
| public static final String FEATURE_FLAGS_CLASS = "android.util.FeatureFlagUtils"; | |
| private static final String LOG_TAG = "FeatureFlagUtils"; | |
| /** | |
| * Get all feature flags in their raw form. | |
| */ | |
| public static Map<String, String> getAllFeatureFlags() { | |
| ReflectionUtils.bypassHiddenAPIReflectionRestrictions(); | |
| try { | |
| Class<?> clazz = Class.forName(FEATURE_FLAGS_CLASS); | |
| Method getAllFeatureFlagsMethod = ReflectionUtils.getDeclaredMethod(clazz, "getAllFeatureFlags"); | |
| if (getAllFeatureFlagsMethod == null) return null; | |
| return (Map<String, String>) ReflectionUtils.invokeMethod(getAllFeatureFlagsMethod, null).value; | |
| } catch (Exception e) { | |
| // ClassCastException may be thrown | |
| Logger.logStackTraceWithMessage(LOG_TAG, "Failed to get all feature flags", e); | |
| return null; | |
| } | |
| } | |
| /** | |
| * Check if a feature flag exists. | |
| * | |
| * @return Returns {@code true} if flag exists, otherwise {@code false}. This will be | |
| * {@code null} if an exception is raised. | |
| */ | |
| public static Boolean featureFlagExists( String feature) { | |
| Map<String, String> featureFlags = getAllFeatureFlags(); | |
| if (featureFlags == null) return null; | |
| return featureFlags.containsKey(feature); | |
| } | |
| /** | |
| * Get {@link FeatureFlagValue} for a feature. | |
| * | |
| * @param context The {@link Context} for operations. | |
| * @param feature The {@link String} name for feature. | |
| * @return Returns {@link FeatureFlagValue}. | |
| */ | |
| public static FeatureFlagValue getFeatureFlagValueString( Context context, String feature) { | |
| Boolean featureFlagExists = featureFlagExists(feature); | |
| if (featureFlagExists == null) { | |
| Logger.logError(LOG_TAG, "Failed to get feature flags \"" + feature + "\" value"); | |
| return FeatureFlagValue.UNKNOWN; | |
| } else if (!featureFlagExists) { | |
| return FeatureFlagValue.UNSUPPORTED; | |
| } | |
| Boolean featureFlagValue = isFeatureEnabled(context, feature); | |
| if (featureFlagValue == null) { | |
| Logger.logError(LOG_TAG, "Failed to get feature flags \"" + feature + "\" value"); | |
| return FeatureFlagValue.UNKNOWN; | |
| } else { | |
| return featureFlagValue ? FeatureFlagValue.TRUE : FeatureFlagValue.FALSE; | |
| } | |
| } | |
| /** | |
| * Check if a feature flag exists. | |
| * | |
| * @param context The {@link Context} for operations. | |
| * @param feature The {@link String} name for feature. | |
| * @return Returns {@code true} if flag exists, otherwise {@code false}. This will be | |
| * {@code null} if an exception is raised. | |
| */ | |
| public static Boolean isFeatureEnabled( Context context, String feature) { | |
| ReflectionUtils.bypassHiddenAPIReflectionRestrictions(); | |
| try { | |
| Class<?> clazz = Class.forName(FEATURE_FLAGS_CLASS); | |
| Method isFeatureEnabledMethod = ReflectionUtils.getDeclaredMethod(clazz, "isEnabled", Context.class, String.class); | |
| if (isFeatureEnabledMethod == null) { | |
| Logger.logError(LOG_TAG, "Failed to check if feature flag \"" + feature + "\" is enabled"); | |
| return null; | |
| } | |
| return (boolean) ReflectionUtils.invokeMethod(isFeatureEnabledMethod, null, context, feature).value; | |
| } catch (Exception e) { | |
| // ClassCastException may be thrown | |
| Logger.logStackTraceWithMessage(LOG_TAG, "Failed to check if feature flag \"" + feature + "\" is enabled", e); | |
| return null; | |
| } | |
| } | |
| } | |
Xet Storage Details
- Size:
- 7.85 kB
- Xet hash:
- 5da9f48952177d8be2e37e01cfd69f6e2c49891437d9e0d51a23c0cc1edfcb46
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.