Field Summary
Modifier and TypeFieldDescriptionprivate static final intAndroid SDK level we run on, zero if not Android.private static intCached CPU core count, computed lazily on firstgetCores()call.private static intCached getCPULoad() result, 0..100.private static longLast wall-clock ms agetCPULoad()OS query ran, or 0 if never.private static RateStatCached "router.cpuLoad" RateStat handle, or null if unresolved.private static StatManagerContext that_cpuLoadStatwas resolved against.private static final I2PAppContextThe global app context, for the config.private static final booleanTrue if the JVM is Java 18.private static final booleanTrue if the JVM is Java 15.private static final booleanTrue if the JVM is Java 14.private static final booleanTrue if the Tanuki wrapper runs us.private static final booleanTrue if the JVM is 64-bit.private static final booleanTrue if running on Android.private static final booleanTrue if running on the Apache Harmony JVM.private static final booleanSystem.getProperty("os.arch").startsWith("aarch"); True if the CPU is ARM.private static final booleanSystem.getProperty("os.version").contains("hardened"); // Funtoo True if the kernel is a Gentoo build.private static final booleanTrue if running on the GNU Java runtime.private static final booleanTrue if running as a Linux service.private static final booleanTrue if running on macOS.private static final booleanTrue if running on OpenJDK.private static final booleanTrue if running as a service of any kind.private static final booleanTrue on devices where features should be limited.private static final booleanTrue if running on Windows.private static final booleanTrue if running as a Windows service.private static final booleanSystem.getProperty("os.arch").equals("amd64"); True if the CPU is x86.private static final booleanTrue if the JVM uses the Zero interpreter.private static final booleanTrue if the JVM is Java 19.private static final booleanTrue if the JVM is Java 1.8.private static final booleanTrue if the JVM is Java 11.private static final booleanTrue if the JVM is Java 9.private static final booleanTrue if the JVM is Java 1.7.private static final booleanTrue if the JVM is Java 1.6.private static final booleanTrue if the JVM is Java 10.private static final booleanTrue if the JVM is Java 17.private static final booleanTrue if the JVM is Java 16.private static intCached getSystemLoad() result, 0..100.private static longLast wall-clock ms agetSystemLoad()OS query ran, or 0 if never.private static final booleanTrue if the JVM is Java 13.private static final booleanTrue if the JVM is Java 12.private static final booleanTrue if the JVM is Java 20.private static final booleanTrue if the JVM is Java 24.private static final booleanTrue if the JVM is Java 21.private static final booleanTrue if the JVM is Java 23.private static final booleanTrue if the JVM is Java 22.static final intDefault window forgetTunnelBuildSuccessRatio(StatManager, int).private static final PatternSplits a comma-separated list.(package private) static final longMinimum interval between two OS queries for the process CPU load.static final StringThe account name a packaged Linux service runs the router under.static final booleanWith no override configured, slow platforms are still detected automatically.static final StringThe account name the Gentoo package runs the router service under, which differs from the one the other distributions use.static final StringSet to true to drop the single-core, low-memory term fromisSlow(), so a small router can still be treated as fast.(package private) static final longMinimum interval between two OS queries for the system load average.Constructor Summary
ConstructorsModifierConstructorDescriptionprotectedThe host environment the router runs on, as reported by the OS and JVM properties probed below.Method Summary
Modifier and TypeMethodDescriptionstatic doublebuildSuccessRatio(double success, double reject, double expire) Successes over all settled builds.(package private) static booleancpuLoadCacheStale(long lastQueried, long now) Whether the cached CPU load sample is old enough to refresh.static intReturns the current number of active (live) threads in the JVM.static intIdentical toandroid.os.Build.VERSION.SDK_INT.static StringgetArch()Returns the architecture of the system running I2P as a string for reference inclients.configand plugin.config files.static intgetCores()Total CPUs including parked/offline cores.static intRetrieve CPU Load of the JVM.static intRetrieve CPU Load Average of the JVM.static double60s-smoothed process CPU load expressed in cores, e.g.private static RateStatResolve and cache the "router.cpuLoad" RateStat handle.static longRuntime.getRuntime().maxMemory()but check for bogus values.static StringgetOS()Returns the OS of the system running I2P as a lower-case string for reference inclients.configand plugin.config files.private static RategetStatRate(StatManager sm, String name, int duration) Returns one stat's rate for a period.static intRetrieve the system load as a percentage, where 100% equals full system load.static TimeZoneThe system's time zone, which is probably different from the JVM time zone, because Router changes the JVM default to GMT.static TimeZoneThe system's time zone, which is probably different from the JVM time zone, because Router changes the JVM default to GMT.static intRetrieve Tunnel build success as a percentage.static doublegetTunnelBuildSuccessRatio(StatManager sm, int windowMs) The canonical tunnel build success ratio: successes over all settled builds, 0.0 to 1.0, for a stated window.static booleanIs the wrapper present? Same asI2PAppContext.hasWrapper().static booleanis64Bit()This isn't always correct.static booleanWhether the OS is Android.static booleanisApache()Apache Harmony JVM, or Android.static booleanisARM()Speed: do not cripple down for powerful ARM.static booleanisGentoo()True if Gentoo.static booleanisGNU()Gij or JamVM with GNU Classpath.static booleanisJava(int minVersion) Handles Android also.static booleanHandles Android, and minVersions in both forms (e.g.static booleanisJava10()True if the JVM is Java 10 or higher, false for Android.static booleanisJava11()True if the JVM is Java 11 or higher, false for Android.static booleanisJava12()True if the JVM is Java 12 or higher, false for Android.static booleanisJava13()True if the JVM is Java 13 or higher, false for Android.static booleanisJava14()True if the JVM is Java 14 or higher, false for Android.static booleanisJava15()True if the JVM is Java 15 or higher, false for Android.static booleanisJava16()True if the JVM is Java 16 or higher, false for Android.static booleanisJava17()True if the JVM is Java 17 or higher, false for Android.static booleanisJava18()True if the JVM is Java 18 or higher, false for Android.static booleanisJava19()True if the JVM is Java 19 or higher, false for Android.static booleanisJava20()True if the JVM is Java 20 or higher, false for Android.static booleanisJava21()True if the JVM is Java 21 or higher, false for Android.static booleanisJava22()True if the JVM is Java 22 or higher, false for Android.static booleanisJava6()Better than (new VersionComparator()).compare(System.getProperty(String)"java.version"), "1.6") >= 0 as it handles Android also, where java.version = "0".static booleanisJava7()Better than (new VersionComparator()).compare(System.getProperty(String)"java.version"), "1.7") >= 0 as it handles Android also, where java.version = "0".static booleanisJava8()True if the JVM is Java 8 or higher, false for Android.static booleanisJava9()True if the JVM is Java 9 or higher, false for Android.static booleanWhether running as a Linux service.static booleanisMac()Whether the OS is Mac.static booleanTrue if OpenJDK.static booleanWhether running as a service under either platform.static booleanisSlow()Our best guess on whether this is a slow architecture / OS / JVM, using some simple heuristics.static booleanWhether the OS is Windows.static booleanWhether running as a Windows service.static booleanisX86()True if x86.static booleanisZeroVM()Is this a very slow interpreted mode VM?static voidPrint the Java version and VM this router is running under, for diagnosing a user-reported problem from the console output.(package private) static booleansysLoadCacheStale(long lastQueried, long now) Whether the cached system load sample is old enough to refresh.static intCalculate how many (virtual) cores should be actually used by a thread pool.
Field Details
DAEMON_USER
The account name a packaged Linux service runs the router under.- See Also:
GENTOO_USER
The account name the Gentoo package runs the router service under, which differs from the one the other distributions use.- See Also:
_isWin
private static final boolean _isWinTrue if running on Windows._isMac
private static final boolean _isMacTrue if running on macOS._isArm
private static final boolean _isArmSystem.getProperty("os.arch").startsWith("aarch"); True if the CPU is ARM._isX86
private static final boolean _isX86System.getProperty("os.arch").equals("amd64"); True if the CPU is x86._isGentoo
private static final boolean _isGentooSystem.getProperty("os.version").contains("hardened"); // Funtoo True if the kernel is a Gentoo build._isZero
private static final boolean _isZeroTrue if the JVM uses the Zero interpreter._isAndroid
private static final boolean _isAndroidTrue if running on Android._isApache
private static final boolean _isApacheTrue if running on the Apache Harmony JVM._isGNU
private static final boolean _isGNUTrue if running on the GNU Java runtime._isOpenJDK
private static final boolean _isOpenJDKTrue if running on OpenJDK._is64
private static final boolean _is64True if the JVM is 64-bit._hasWrapper
private static final boolean _hasWrapperTrue if the Tanuki wrapper runs us._isLinuxService
private static final boolean _isLinuxServiceTrue if running as a Linux service._isWindowsService
private static final boolean _isWindowsServiceTrue if running as a Windows service._isService
private static final boolean _isServiceTrue if running as a service of any kind._isSlow
private static final boolean _isSlowTrue on devices where features should be limited._cores
private static volatile int _coresCached CPU core count, computed lazily on firstgetCores()call.CPU_LOAD_CACHE_MS
static final long CPU_LOAD_CACHE_MSMinimum interval between two OS queries for the process CPU load. Each query is expensive (on JDK 19+ the MXBean reads /proc via Files.lines), and the value is only used for coarse throttling/backoff, so a 1-second cache is plenty.- See Also:
_cpuLoadQueried
private static volatile long _cpuLoadQueriedLast wall-clock ms agetCPULoad()OS query ran, or 0 if never._cpuLoad
private static volatile int _cpuLoadCached getCPULoad() result, 0..100.SYSTEM_LOAD_CACHE_MS
static final long SYSTEM_LOAD_CACHE_MSMinimum interval between two OS queries for the system load average. getSystemLoadAverage() is a native call (JDK reads /proc/loadavg), far more expensive than a map lookup, and it sits on the per-build-request path of both tunnel throttlers. The load average is itself a 1/5/15 minute metric, so 1s of staleness is far below its own resolution.- See Also:
_sysLoadQueried
private static volatile long _sysLoadQueriedLast wall-clock ms agetSystemLoad()OS query ran, or 0 if never._sysLoad
private static volatile int _sysLoadCached getSystemLoad() result, 0..100._cpuLoadStat
Cached "router.cpuLoad" RateStat handle, or null if unresolved.getCPULoadAvg()previously did two string-keyed statManager() lookups per call across a dozen call sites (JobQueue pumper, both throttlers, peer tests). The stat is created once at startup and never replaced, so the handle is resolved once and reused until the context changes._cpuLoadStatCtx
Context that_cpuLoadStatwas resolved against._oneDotSix
private static final boolean _oneDotSixTrue if the JVM is Java 1.6._oneDotSeven
private static final boolean _oneDotSevenTrue if the JVM is Java 1.7._oneDotEight
private static final boolean _oneDotEightTrue if the JVM is Java 1.8._oneDotNine
private static final boolean _oneDotNineTrue if the JVM is Java 9._oneDotTen
private static final boolean _oneDotTenTrue if the JVM is Java 10._oneDotEleven
private static final boolean _oneDotElevenTrue if the JVM is Java 11._twelve
private static final boolean _twelveTrue if the JVM is Java 12._thirteen
private static final boolean _thirteenTrue if the JVM is Java 13._fourteen
private static final boolean _fourteenTrue if the JVM is Java 14._fifteen
private static final boolean _fifteenTrue if the JVM is Java 15._sixteen
private static final boolean _sixteenTrue if the JVM is Java 16._seventeen
private static final boolean _seventeenTrue if the JVM is Java 17._eighteen
private static final boolean _eighteenTrue if the JVM is Java 18._nineteen
private static final boolean _nineteenTrue if the JVM is Java 19._twenty
private static final boolean _twentyTrue if the JVM is Java 20._twentyOne
private static final boolean _twentyOneTrue if the JVM is Java 21._twentyTwo
private static final boolean _twentyTwoTrue if the JVM is Java 22._twentyThree
private static final boolean _twentyThreeTrue if the JVM is Java 23._twentyFour
private static final boolean _twentyFourTrue if the JVM is Java 24._androidSDK
private static final int _androidSDKAndroid SDK level we run on, zero if not Android.PROP_OVERRIDE_IS_SLOW
Set to true to drop the single-core, low-memory term fromisSlow(), so a small router can still be treated as fast. It gates only that term: the Android, ARM, GNU and Zero tests, the non-native BigInteger test, and the under-4-cores 32-bit test still apply.- See Also:
DEFAULT_OVERRIDE_IS_SLOW
public static final boolean DEFAULT_OVERRIDE_IS_SLOWWith no override configured, slow platforms are still detected automatically.- See Also:
COMMA_SPLIT
Splits a comma-separated list._ctx
The global app context, for the config.BUILD_SUCCESS_WINDOW_MS
public static final int BUILD_SUCCESS_WINDOW_MSDefault window forgetTunnelBuildSuccessRatio(StatManager, int). Ten minutes: long enough that a single bad minute is not mistaken for sustained failure, short enough to react within one LeaseSet refresh cycle.- See Also:
Constructor Details
SystemVersion
protected SystemVersion()The host environment the router runs on, as reported by the OS and JVM properties probed below. No state is held per instance; the probes are static and cache their own results.
Method Details
getOS
Returns the OS of the system running I2P as a lower-case string for reference inclients.configand plugin.config files.matches the conventions of the Go cross compiler.
- Returns:
- the OS of the system running I2P as a lower-case string
getArch
Returns the architecture of the system running I2P as a string for reference inclients.configand plugin.config files.matches the conventions of the Go cross compiler.
- Returns:
- the architecture of the system running I2P as a string
isWindows
public static boolean isWindows()Whether the OS is Windows.- Returns:
- true when os.name starts with "Win", resolved once at class load
isMac
public static boolean isMac()Whether the OS is Mac.- Returns:
- true when os.name starts with "Mac", resolved once at class load
isAndroid
public static boolean isAndroid()Whether the OS is Android.- Returns:
- true when java.vendor contains "Android"
isApache
public static boolean isApache()Apache Harmony JVM, or Android.- Returns:
- true when java.vendor starts with "Apache", or on Android
isGNU
public static boolean isGNU()Gij or JamVM with GNU Classpath.- Returns:
- true if running on the GNU Java runtime
isGentoo
public static boolean isGentoo()True if Gentoo.- Returns:
- true when os.version names gentoo or a hardened kernel
isOpenJDK
public static boolean isOpenJDK()True if OpenJDK.- Returns:
- whether open j d k
isARM
public static boolean isARM()Speed: do not cripple down for powerful ARM.- Returns:
- whether a r m
isX86
public static boolean isX86()True if x86.- Returns:
- whether x86
isZeroVM
public static boolean isZeroVM()Is this a very slow interpreted mode VM?- Returns:
- whether zero v m
isSlow
public static boolean isSlow()Our best guess on whether this is a slow architecture / OS / JVM, using some simple heuristics.- Returns:
- the cached verdict, OR-ed with a live core count, native big integer, and heap size check that is suppressed by the override property
isJava6
public static boolean isJava6()Better than (new VersionComparator()).compare(System.getProperty(String)"java.version"), "1.6") >= 0 as it handles Android also, where java.version = "0".- Returns:
- true if Java 1.6 or higher, or Android API 9 or higher
isJava7
public static boolean isJava7()Better than (new VersionComparator()).compare(System.getProperty(String)"java.version"), "1.7") >= 0 as it handles Android also, where java.version = "0".- Returns:
- true if Java 1.7 or higher, or Android API 19 or higher
isJava8
public static boolean isJava8()True if the JVM is Java 8 or higher, false for Android.- Returns:
- true if Java 1.8 or higher, false for Android.
isJava9
public static boolean isJava9()True if the JVM is Java 9 or higher, false for Android.- Returns:
- true if Java 9 or higher, false for Android.
isJava10
public static boolean isJava10()True if the JVM is Java 10 or higher, false for Android.- Returns:
- true if Java 10 or higher, false for Android.
isJava11
public static boolean isJava11()True if the JVM is Java 11 or higher, false for Android.- Returns:
- true if Java 11 or higher, false for Android.
isJava12
public static boolean isJava12()True if the JVM is Java 12 or higher, false for Android.- Returns:
- true if Java 12 or higher, false for Android.
isJava13
public static boolean isJava13()True if the JVM is Java 13 or higher, false for Android.- Returns:
- true if Java 13 or higher, false for Android.
isJava14
public static boolean isJava14()True if the JVM is Java 14 or higher, false for Android.- Returns:
- true if Java 14 or higher, false for Android.
isJava15
public static boolean isJava15()True if the JVM is Java 15 or higher, false for Android.- Returns:
- true if Java 15 or higher, false for Android.
isJava16
public static boolean isJava16()True if the JVM is Java 16 or higher, false for Android.- Returns:
- true if Java 16 or higher, false for Android.
isJava17
public static boolean isJava17()True if the JVM is Java 17 or higher, false for Android.- Returns:
- true if Java 17 or higher, false for Android.
isJava18
public static boolean isJava18()True if the JVM is Java 18 or higher, false for Android.- Returns:
- true if Java 18 or higher, false for Android.
isJava19
public static boolean isJava19()True if the JVM is Java 19 or higher, false for Android.- Returns:
- true if Java 19 or higher, false for Android.
isJava20
public static boolean isJava20()True if the JVM is Java 20 or higher, false for Android.- Returns:
- true if Java 20 or higher, false for Android.
isJava21
public static boolean isJava21()True if the JVM is Java 21 or higher, false for Android.- Returns:
- true if Java 21 or higher, false for Android.
isJava22
public static boolean isJava22()True if the JVM is Java 22 or higher, false for Android.- Returns:
- true if Java 21 or higher, false for Android.
isJava
public static boolean isJava(int minVersion) Handles Android also.- Parameters:
minVersion- e.g. 11- Returns:
- true if greater than or equal to minVersion
isJava
Handles Android, and minVersions in both forms (e.g. 11 or 1.11).- Parameters:
minVersion- either 1.x or x form works- Returns:
- true if greater than or equal to minVersion
is64Bit
public static boolean is64Bit()This isn't always correct. http://stackoverflow.com/questions/807263/how-do-i-detect-which-kind-of-jre-is-installed-32bit-vs-64bit os.arch is the bitness of the JREchecking OS bitness on Windowssun.arch.data.modelnot on all JVMssun.arch.data.model== 64 => 64 bit processorsun.arch.data.model== 32 => A 32 bit JVM but could be either 32 or 64 bit processor or libs os.arch contains "64" could be 32 or 64 bit libs.- Returns:
- whether 64 bit
isLinuxService
public static boolean isLinuxService()Whether running as a Linux service.- Returns:
- whether linux service
isWindowsService
public static boolean isWindowsService()Whether running as a Windows service.- Returns:
- whether windows service
isService
public static boolean isService()Whether running as a service under either platform.- Returns:
- true for a Linux daemon user or a Tanuki wrapper on Windows
getAndroidVersion
public static int getAndroidVersion()Identical toandroid.os.Build.VERSION.SDK_INT. For use outside of Android code.- Returns:
- The SDK (API) version, e.g. 8 for Froyo, 0 if unknown
hasWrapper
public static boolean hasWrapper()Is the wrapper present? Same asI2PAppContext.hasWrapper().- Returns:
- whether wrapper is present
getMaxMemory
public static long getMaxMemory()Runtime.getRuntime().maxMemory()but check for bogus values.- Returns:
- the max memory
getCores
public static int getCores()Total CPUs including parked/offline cores. On Linux, reads /sys/devices/system/cpu/present to get the full CPU topology regardless of cpufreq governor parking. Falls back toRuntime.getRuntime().availableProcessors().- Returns:
- never smaller than 1
usableCores
public static int usableCores()Calculate how many (virtual) cores should be actually used by a thread pool.- Returns:
- 1 on Windows and macOS, or 3/4 of the logical cores on x86
getSystemTimeZone
The system's time zone, which is probably different from the JVM time zone, because Router changes the JVM default to GMT. It saves the old default in the context properties where we can get it. Use this to format a time in local time zone withDateFormat.setTimeZone().- Returns:
- non-null
getSystemTimeZone
The system's time zone, which is probably different from the JVM time zone, because Router changes the JVM default to GMT. It saves the old default in the context properties where we can get it. Use this to format a time in local time zone withDateFormat.setTimeZone().- Parameters:
ctx- the application context whose properties hold the saved system time zone ID- Returns:
- the saved system time zone, or the JVM default if none was saved
main
Print the Java version and VM this router is running under, for diagnosing a user-reported problem from the console output.- Parameters:
args- ignored, no arguments are parsed
getCPULoad
public static int getCPULoad()Retrieve CPU Load of the JVM.The MXBean query is expensive — on JDK 19+ each call reads /proc via Files.lines. So results are cached for
CPU_LOAD_CACHE_MS. Callers such as the JobQueue pumper and the throttlers only need a coarse periodic sample, so up to 1s of staleness is acceptable.- Returns:
- the CPU load
cpuLoadCacheStale
static boolean cpuLoadCacheStale(long lastQueried, long now) Whether the cached CPU load sample is old enough to refresh. Never-queried (lastQueried == 0) counts as stale so the first call always queries the MXBean instead of returning the 0 initializer.- Parameters:
lastQueried- the wall-clock ms of the previous query, or 0now- the current wall-clock ms- Returns:
- true if the cache should be refreshed
sysLoadCacheStale
static boolean sysLoadCacheStale(long lastQueried, long now) Whether the cached system load sample is old enough to refresh. Never-queried (lastQueried == 0) counts as stale so the first call always queries the MXBean instead of returning the 0 initializer. A wall-clock step backwards (NTP correction, manual change) also counts as stale: a plain age comparison would report the sample as fresh until the clock caught up again, pinning a stale value for the length of the step.- Parameters:
lastQueried- the wall-clock ms of the previous query, or 0now- the current wall-clock ms- Returns:
- true if the cache should be refreshed
getCpuLoadStat
Resolve and cache the "router.cpuLoad" RateStat handle. The stat is registered once during startup and never replaced, so the handle stays valid for the life of the context. Re-resolves if the context or its StatManager is swapped (as in unit tests).- Returns:
- the cached stat, or null if it is not registered yet
getCPULoadAvg
public static int getCPULoadAvg()Retrieve CPU Load Average of the JVM.- Returns:
- the CPU load avg
getCPULoadCores
public static double getCPULoadCores()60s-smoothed process CPU load expressed in cores, e.g. 2.3 on a 4-core machine means the JVM recently consumed 2.3 cores on average.- Returns:
- the cores used, from 0.0 to getCores()
getSystemLoad
public static int getSystemLoad()Retrieve the system load as a percentage, where 100% equals full system load.The MXBean query is a native /proc read and is cached for
SYSTEM_LOAD_CACHE_MS, because this sits on the per-request path of both tunnel throttlers while the underlying load average moves on a multi-minute timescale.- Returns:
- the system load
getActiveThreads
public static int getActiveThreads()Returns the current number of active (live) threads in the JVM. This includes both daemon and non-daemon threads.- Returns:
- the estimated number of active threads, or 0 if context or stat manager is unavailable
getStatRate
Returns one stat's rate for a period.- Parameters:
sm- the stat managername- the stat nameduration- the rate period, in ms- Returns:
- the rate, or null if the stat is unknown
getTunnelBuildSuccess
public static int getTunnelBuildSuccess()Retrieve Tunnel build success as a percentage.- Returns:
- the tunnel build success
getTunnelBuildSuccessRatio
The canonical tunnel build success ratio: successes over all settled builds, 0.0 to 1.0, for a stated window.This is the single source of truth. Three implementations existed and none of them agreed:
ProfileOrganizerreadgetCurrentEventCount()- the current partial period - while asking for the ten minute rate, so it sampled a fraction of one bucket and threw the history away; the copy here readgetLastEventCount(), the last completed period; and the Tuner used a different set of stats entirely on an hourly window. That value is not cosmetic - it gates profile eviction, selects the ghost cooldown, and feedsClientPeerSelectorfirst-hop selection - so a partial-period reading could intermittently drop it under the attack threshold and switch all three to their defensive behaviour on noise.Counts events over the last completed window rather than the current partial one, so the reading does not depend on where in the period it was sampled. Partial-period sampling was what made the old value swing, and swing under the attack threshold, which switches off profile eviction and lengthens ghost cooldowns.
- Parameters:
sm- the stat manager, or nullwindowMs- the averaging window in milliseconds- Returns:
- the ratio, or NaN if the stats are absent or the window is empty
buildSuccessRatio
public static double buildSuccessRatio(double success, double reject, double expire) Successes over all settled builds. Pure arithmetic, so it is testable without stats.- Parameters:
success- mean successes per periodreject- mean rejections per periodexpire- mean expiries per period- Returns:
- the ratio, or NaN when nothing settled in the window