package evanq.game.utils; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.net.InetSocketAddress; import java.net.ServerSocket; import java.util.Locale; import java.util.concurrent.BlockingQueue; import java.util.regex.Pattern; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * * 检测平台的信息 * * @author Evan cppmain@gmail.com * */ public final class PlatformUtils { private static final Logger logger = LoggerFactory .getLogger(PlatformUtils.class); private static final boolean IS_ANDROID = isAndroid0(); private static final boolean IS_WINDOWS = isWindows0(); private static final boolean IS_ROOT = isRoot0(); private static final int JAVA_VERSION = javaVersion0(); /** * Returns {@code true} if and only if the current platform is Android */ public static boolean isAndroid() { return IS_ANDROID; } /** * Return {@code true} if the JVM is running on Windows */ public static boolean isWindows() { return IS_WINDOWS; } /** * Return {@code true} if the current user is root. Note that this method * returns {@code false} if on Windows. */ public static boolean isRoot() { return IS_ROOT; } /** * Return the version of Java under which this library is used. */ public static int javaVersion() { return JAVA_VERSION; } @SuppressWarnings("LoopStatementThatDoesntLoop") private static int javaVersion0() { int javaVersion; // Not really a loop for (;;) { // Android if (isAndroid()) { javaVersion = 6; break; } try { Class.forName("java.time.Clock", false, Object.class.getClassLoader()); javaVersion = 8; break; } catch (Exception e) { // Ignore } try { Class.forName("java.util.concurrent.LinkedTransferQueue", false, BlockingQueue.class.getClassLoader()); javaVersion = 7; break; } catch (Exception e) { // Ignore } javaVersion = 6; break; } if (logger.isDebugEnabled()) { logger.debug("Java version: {}", javaVersion); } return javaVersion; } private static boolean isAndroid0() { boolean android; try { Class.forName("android.app.Application", false, ClassLoader.getSystemClassLoader()); android = true; } catch (Exception e) { android = false; } if (android) { logger.debug("Platform: Android"); } return android; } private static boolean isWindows0() { boolean windows = SystemPropertyUtil.get("os.name", "") .toLowerCase(Locale.US).contains("win"); if (windows) { logger.debug("Platform: Windows"); } return windows; } private static boolean isRoot0() { if (isWindows()) { return false; } String[] ID_COMMANDS = { "/usr/bin/id", "/bin/id", "id" }; Pattern UID_PATTERN = Pattern.compile("^(?:0|[1-9][0-9]*)$"); for (String idCmd : ID_COMMANDS) { Process p = null; BufferedReader in = null; String uid = null; try { p = Runtime.getRuntime().exec(new String[] { idCmd, "-u" }); in = new BufferedReader(new InputStreamReader( p.getInputStream(), CharsetUtil.US_ASCII)); uid = in.readLine(); in.close(); for (;;) { try { int exitCode = p.waitFor(); if (exitCode != 0) { uid = null; } break; } catch (InterruptedException e) { // Ignore } } } catch (Exception e) { uid = null; } finally { if (in != null) { try { in.close(); } catch (IOException e) { // Ignore } } if (p != null) { try { p.destroy(); } catch (Exception e) { // Android sometimes triggers an ErrnoException. } } } if (uid != null && UID_PATTERN.matcher(uid).matches()) { logger.debug("UID: {}", uid); return "0".equals(uid); } } logger.debug("Could not determine the current UID using /usr/bin/id; attempting to bind at privileged ports."); Pattern PERMISSION_DENIED = Pattern .compile(".*(?:denied|not.*permitted).*"); for (int i = 1023; i > 0; i--) { ServerSocket ss = null; try { ss = new ServerSocket(); ss.setReuseAddress(true); ss.bind(new InetSocketAddress(i)); if (logger.isDebugEnabled()) { logger.debug("UID: 0 (succeded to bind at port {})", i); } return true; } catch (Exception e) { // Failed to bind. // Check the error message so that we don't always need to bind // 1023 times. String message = e.getMessage(); if (message == null) { message = ""; } message = message.toLowerCase(); if (PERMISSION_DENIED.matcher(message).matches()) { break; } } finally { if (ss != null) { try { ss.close(); } catch (Exception e) { // Ignore. } } } } logger.debug("UID: non-root (failed to bind at any privileged ports)"); return false; } }