PlatformUtils: move OS/runtime detection from o.b.core.Utils to new class

This commit is contained in:
Sean Gilligan 2023-02-27 09:18:31 -08:00 committed by Andreas Schildbach
parent 0685bf70e4
commit 6e77dcb433
14 changed files with 153 additions and 94 deletions

View file

@ -0,0 +1,89 @@
/*
* Copyright by the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.bitcoinj.base.internal;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Locale;
/**
* Utilities for determining platform information (OS and runtime)
*/
public class PlatformUtils {
private static final Logger log = LoggerFactory.getLogger(PlatformUtils.class);
public enum Runtime {
ANDROID, OPENJDK, ORACLE_JAVA
}
public enum OS {
LINUX, WINDOWS, MAC_OS
}
public static Runtime runtime = null;
public static OS os = null;
static {
String runtimeProp = System.getProperty("java.runtime.name", "").toLowerCase(Locale.US);
if (runtimeProp.equals(""))
PlatformUtils.runtime = null;
else if (runtimeProp.contains("android"))
PlatformUtils.runtime = PlatformUtils.Runtime.ANDROID;
else if (runtimeProp.contains("openjdk"))
PlatformUtils.runtime = PlatformUtils.Runtime.OPENJDK;
else if (runtimeProp.contains("java(tm) se"))
PlatformUtils.runtime = PlatformUtils.Runtime.ORACLE_JAVA;
else
log.info("Unknown java.runtime.name '{}'", runtimeProp);
String osProp = System.getProperty("os.name", "").toLowerCase(Locale.US);
if (osProp.equals(""))
PlatformUtils.os = null;
else if (osProp.contains("linux"))
PlatformUtils.os = PlatformUtils.OS.LINUX;
else if (osProp.contains("win"))
PlatformUtils.os = PlatformUtils.OS.WINDOWS;
else if (osProp.contains("mac"))
PlatformUtils.os = PlatformUtils.OS.MAC_OS;
else
log.info("Unknown os.name '{}'", runtimeProp);
}
public static boolean isAndroidRuntime() {
return runtime == Runtime.ANDROID;
}
public static boolean isOpenJDKRuntime() {
return runtime == Runtime.OPENJDK;
}
public static boolean isOracleJavaRuntime() {
return runtime == Runtime.ORACLE_JAVA;
}
public static boolean isLinux() {
return os == OS.LINUX;
}
public static boolean isWindows() {
return os == OS.WINDOWS;
}
public static boolean isMac() {
return os == OS.MAC_OS;
}
}

View file

@ -27,6 +27,7 @@ import com.google.common.util.concurrent.Runnables;
import com.google.common.util.concurrent.Uninterruptibles;
import net.jcip.annotations.GuardedBy;
import org.bitcoinj.base.Network;
import org.bitcoinj.base.internal.PlatformUtils;
import org.bitcoinj.core.listeners.AddressEventListener;
import org.bitcoinj.core.listeners.BlockchainDownloadEventListener;
import org.bitcoinj.core.listeners.BlocksDownloadedEventListener;
@ -542,7 +543,7 @@ public class PeerGroup implements TransactionBroadcaster {
// First run: try and use a local node if there is one, for the additional security it can provide.
// But, not on Android as there are none for this platform: it could only be a malicious app trying
// to hijack our traffic.
if (!Utils.isAndroidRuntime() && useLocalhostPeerWhenPossible && maybeCheckForLocalhostPeer() && firstRun) {
if (!PlatformUtils.isAndroidRuntime() && useLocalhostPeerWhenPossible && maybeCheckForLocalhostPeer() && firstRun) {
log.info("Localhost peer detected, trying to use it instead of P2P discovery");
maxConnections = 0;
connectToLocalHost();

View file

@ -148,66 +148,6 @@ public class Utils {
return iso8601.format(dateTime);
}
private enum Runtime {
ANDROID, OPENJDK, ORACLE_JAVA
}
private enum OS {
LINUX, WINDOWS, MAC_OS
}
private static Runtime runtime = null;
private static OS os = null;
static {
String runtimeProp = System.getProperty("java.runtime.name", "").toLowerCase(Locale.US);
if (runtimeProp.equals(""))
runtime = null;
else if (runtimeProp.contains("android"))
runtime = Runtime.ANDROID;
else if (runtimeProp.contains("openjdk"))
runtime = Runtime.OPENJDK;
else if (runtimeProp.contains("java(tm) se"))
runtime = Runtime.ORACLE_JAVA;
else
log.info("Unknown java.runtime.name '{}'", runtimeProp);
String osProp = System.getProperty("os.name", "").toLowerCase(Locale.US);
if (osProp.equals(""))
os = null;
else if (osProp.contains("linux"))
os = OS.LINUX;
else if (osProp.contains("win"))
os = OS.WINDOWS;
else if (osProp.contains("mac"))
os = OS.MAC_OS;
else
log.info("Unknown os.name '{}'", runtimeProp);
}
public static boolean isAndroidRuntime() {
return runtime == Runtime.ANDROID;
}
public static boolean isOpenJDKRuntime() {
return runtime == Runtime.OPENJDK;
}
public static boolean isOracleJavaRuntime() {
return runtime == Runtime.ORACLE_JAVA;
}
public static boolean isLinux() {
return os == OS.LINUX;
}
public static boolean isWindows() {
return os == OS.WINDOWS;
}
public static boolean isMac() {
return os == OS.MAC_OS;
}
public static String toString(List<byte[]> stack) {
List<String> parts = new ArrayList<>(stack.size());
for (byte[] push : stack)

View file

@ -19,8 +19,8 @@ package org.bitcoinj.crypto;
import com.google.common.base.Stopwatch;
import org.bitcoinj.base.Sha256Hash;
import org.bitcoinj.base.internal.PlatformUtils;
import org.bitcoinj.base.utils.StreamUtils;
import org.bitcoinj.core.Utils;
import org.bitcoinj.base.internal.InternalUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -65,7 +65,7 @@ public class MnemonicCode {
INSTANCE = new MnemonicCode();
} catch (FileNotFoundException e) {
// We expect failure on Android. The developer has to set INSTANCE themselves.
if (!Utils.isAndroidRuntime())
if (!PlatformUtils.isAndroidRuntime())
log.error("Could not find word list", e);
} catch (IOException e) {
log.error("Failed to load word list", e);

View file

@ -21,13 +21,13 @@ import com.google.common.io.Closeables;
import com.google.common.util.concurrent.AbstractIdleService;
import org.bitcoinj.base.BitcoinNetwork;
import org.bitcoinj.base.ScriptType;
import org.bitcoinj.base.internal.PlatformUtils;
import org.bitcoinj.core.BlockChain;
import org.bitcoinj.core.CheckpointManager;
import org.bitcoinj.core.Context;
import org.bitcoinj.core.NetworkParameters;
import org.bitcoinj.core.PeerAddress;
import org.bitcoinj.core.PeerGroup;
import org.bitcoinj.core.Utils;
import org.bitcoinj.core.listeners.DownloadProgressTracker;
import org.bitcoinj.crypto.DeterministicKey;
import org.bitcoinj.net.discovery.DnsDiscovery;
@ -329,7 +329,7 @@ public class WalletAppKit extends AbstractIdleService {
// Initiate Bitcoin network objects (block store, blockchain and peer group)
vStore = new SPVBlockStore(params, chainFile);
if (!chainFileExists || restoreFromSeed != null || restoreFromKey != null) {
if (checkpoints == null && !Utils.isAndroidRuntime()) {
if (checkpoints == null && !PlatformUtils.isAndroidRuntime()) {
checkpoints = CheckpointManager.openStream(params);
}

View file

@ -17,8 +17,8 @@
package org.bitcoinj.net.discovery;
import org.bitcoinj.base.internal.PlatformUtils;
import org.bitcoinj.core.NetworkParameters;
import org.bitcoinj.core.Utils;
import org.bitcoinj.core.VersionMessage;
import org.bitcoinj.utils.ContextPropagatingThreadFactory;
import org.bitcoinj.utils.DaemonThreadFactory;
@ -79,7 +79,7 @@ public class DnsDiscovery extends MultiplexingDiscovery {
protected ExecutorService createExecutor() {
// Attempted workaround for reported bugs on Linux in which gethostbyname does not appear to be properly
// thread safe and can cause segfaults on some libc versions.
if (Utils.isLinux())
if (PlatformUtils.isLinux())
return Executors.newSingleThreadExecutor(new ContextPropagatingThreadFactory("DNS seed lookups"));
else
return Executors.newFixedThreadPool(seeds.size(), new DaemonThreadFactory("DNS seed lookups"));

View file

@ -16,7 +16,7 @@
package org.bitcoinj.utils;
import org.bitcoinj.core.Utils;
import org.bitcoinj.base.internal.PlatformUtils;
import java.io.IOException;
import java.nio.file.FileSystems;
@ -64,11 +64,11 @@ public class AppDataDirectory {
public static Path getPath(String appName) {
final Path applicationDataDirectory;
if (Utils.isWindows()) {
if (PlatformUtils.isWindows()) {
applicationDataDirectory = pathOf(System.getenv("APPDATA"), appName.toLowerCase());
} else if (Utils.isMac()) {
} else if (PlatformUtils.isMac()) {
applicationDataDirectory = pathOf(System.getProperty("user.home"),"Library/Application Support", appName);
} else if (Utils.isLinux()) {
} else if (PlatformUtils.isLinux()) {
applicationDataDirectory = pathOf(System.getProperty("user.home"), "." + appName.toLowerCase());
} else {
// Unknown, assume unix-like

View file

@ -20,7 +20,7 @@ import com.google.common.util.concurrent.CycleDetectingLockFactory;
import com.google.common.util.concurrent.ListeningExecutorService;
import com.google.common.util.concurrent.MoreExecutors;
import com.google.common.util.concurrent.Uninterruptibles;
import org.bitcoinj.core.Utils;
import org.bitcoinj.base.internal.PlatformUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -151,7 +151,7 @@ public class Threading {
}
public static ReentrantLock lock(String name) {
if (Utils.isAndroidRuntime())
if (PlatformUtils.isAndroidRuntime())
return new ReentrantLock(true);
else
return factory.newReentrantLock(name);

View file

@ -27,6 +27,7 @@ import net.jcip.annotations.GuardedBy;
import org.bitcoinj.base.BitcoinNetwork;
import org.bitcoinj.base.Network;
import org.bitcoinj.base.exceptions.AddressFormatException;
import org.bitcoinj.base.internal.PlatformUtils;
import org.bitcoinj.base.utils.StreamUtils;
import org.bitcoinj.core.AbstractBlockChain;
import org.bitcoinj.base.Address;
@ -1495,7 +1496,7 @@ public class Wallet extends BaseTaggableObject
stream.getFD().sync();
stream.close();
stream = null;
if (Utils.isWindows()) {
if (PlatformUtils.isWindows()) {
// Work around an issue on Windows whereby you can't rename over existing files.
File canonical = destFile.getCanonicalFile();
if (canonical.exists() && !canonical.delete())

View file

@ -0,0 +1,34 @@
/*
* Copyright by the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.bitcoinj.base.internal;
import org.junit.Test;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
/**
* Tests for PlatformUtils
*/
public class PlatformUtilsTest {
@Test
public void runtime() {
// This test assumes it is run within a Java runtime for desktop computers.
assertTrue(PlatformUtils.isOpenJDKRuntime() || PlatformUtils.isOracleJavaRuntime());
assertFalse(PlatformUtils.isAndroidRuntime());
}
}

View file

@ -34,13 +34,6 @@ public class UtilsTest {
assertEquals("2014-11-16T10:54:33Z", Utils.dateTimeFormat(new Date(1416135273781L)));
}
@Test
public void runtime() {
// This test assumes it is run within a Java runtime for desktop computers.
assertTrue(Utils.isOpenJDKRuntime() || Utils.isOracleJavaRuntime());
assertFalse(Utils.isAndroidRuntime());
}
@Test
public void testRollMockClock() {
Utils.setMockClock(25200);

View file

@ -21,6 +21,7 @@ import com.google.common.base.Stopwatch;
import org.bitcoinj.base.BitcoinNetwork;
import org.bitcoinj.base.ScriptType;
import org.bitcoinj.base.Address;
import org.bitcoinj.base.internal.PlatformUtils;
import org.bitcoinj.core.Block;
import org.bitcoinj.core.Context;
import org.bitcoinj.crypto.ECKey;
@ -182,7 +183,7 @@ public class SPVBlockStoreTest {
SPVBlockStore store = new SPVBlockStore(TESTNET, blockStoreFile);
store.close();
boolean deleted = blockStoreFile.delete();
if (!Utils.isWindows()) {
if (!PlatformUtils.isWindows()) {
// TODO: Deletion is failing on Windows
assertTrue(deleted);
}

View file

@ -17,7 +17,7 @@
package org.bitcoinj.utils;
import org.bitcoinj.core.Utils;
import org.bitcoinj.base.internal.PlatformUtils;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
@ -33,11 +33,11 @@ public class AppDataDirectoryTest {
public void worksOnCurrentPlatform() {
final String appName = "bitcoinj";
String path = AppDataDirectory.get(appName).toString();
if (Utils.isWindows()) {
if (PlatformUtils.isWindows()) {
assertEquals("Path wrong on Windows", winPath(appName), path);
} else if (Utils.isMac()) {
} else if (PlatformUtils.isMac()) {
assertEquals("Path wrong on Mac", macPath(appName), path);
} else if (Utils.isLinux()) {
} else if (PlatformUtils.isLinux()) {
assertEquals("Path wrong on Linux", unixPath(appName), path);
} else {
assertEquals("Path wrong on unknown/default", unixPath(appName), path);
@ -48,11 +48,11 @@ public class AppDataDirectoryTest {
public void worksOnCurrentPlatformForBitcoinCore() {
final String appName = "Bitcoin";
String path = AppDataDirectory.get(appName).toString();
if (Utils.isWindows()) {
if (PlatformUtils.isWindows()) {
assertEquals("Path wrong on Windows", winPath(appName), path);
} else if (Utils.isMac()) {
} else if (PlatformUtils.isMac()) {
assertEquals("Path wrong on Mac", macPath(appName), path);
} else if (Utils.isLinux()) {
} else if (PlatformUtils.isLinux()) {
assertEquals("Path wrong on Linux", unixPath(appName), path);
} else {
assertEquals("Path wrong on unknown/default", unixPath(appName), path);
@ -62,14 +62,14 @@ public class AppDataDirectoryTest {
@Test(expected = RuntimeException.class)
public void throwsIOExceptionIfPathNotFound() {
// Force exceptions with illegal characters
if (Utils.isWindows()) {
if (PlatformUtils.isWindows()) {
AppDataDirectory.get(":"); // Illegal character for Windows
}
if (Utils.isMac()) {
if (PlatformUtils.isMac()) {
// NUL character
AppDataDirectory.get("\0"); // Illegal character for Mac
}
if (Utils.isLinux()) {
if (PlatformUtils.isLinux()) {
// NUL character
AppDataDirectory.get("\0"); // Illegal character for Linux
}

View file

@ -22,9 +22,9 @@ import javafx.scene.input.KeyCombination;
import javafx.stage.Stage;
import org.bitcoinj.base.BitcoinNetwork;
import org.bitcoinj.base.ScriptType;
import org.bitcoinj.base.internal.PlatformUtils;
import org.bitcoinj.core.Context;
import org.bitcoinj.core.NetworkParameters;
import org.bitcoinj.core.Utils;
import org.bitcoinj.kits.WalletAppKit;
import org.bitcoinj.utils.AppDataDirectory;
import org.bitcoinj.utils.BriefLogFormatter;
@ -118,7 +118,7 @@ public abstract class WalletApplication implements AppDelegate {
// Make log output concise.
BriefLogFormatter.init();
if (Utils.isMac()) {
if (PlatformUtils.isMac()) {
// We could match the Mac Aqua style here, except that (a) Modena doesn't look that bad, and (b)
// the date picker widget is kinda broken in AquaFx and I can't be bothered fixing it.
// AquaFx.style();