package jogamp.common.os;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.IntBuffer;
import java.nio.ShortBuffer;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.List;
import jogamp.common.Debug;
import jogamp.common.os.elf.ElfHeader;
import jogamp.common.os.elf.SectionArmAttributes;
import jogamp.common.os.elf.SectionHeader;
import com.jogamp.common.nio.Buffers;
import com.jogamp.common.os.AndroidVersion;
import com.jogamp.common.os.NativeLibrary;
import com.jogamp.common.os.Platform;
import com.jogamp.common.os.Platform.ABIType;
import com.jogamp.common.os.Platform.CPUFamily;
import com.jogamp.common.os.Platform.CPUType;
import com.jogamp.common.os.Platform.OSType;
import com.jogamp.common.util.VersionNumber;
/**
* Abstract parent class of {@link Platform} initializing and holding
* platform information, which are initialized independent
* of other classes.
*
* This class is not intended to be exposed in the public namespace
* and solely exist to solve initialization interdependencies.
* Please use {@link Platform} to access the public fields!
*
*/
public abstract class PlatformPropsImpl {
static final boolean DEBUG = Debug.debug("Platform");
/** Selected {@link Platform.OSType#MACOS} {@link VersionNumber}s. */
public static class OSXVersion {
/** OSX Tiger, i.e. 10.4.0 */
public static final VersionNumber Tiger = new VersionNumber(10,4,0);
/** OSX Lion, i.e. 10.7.0 */
public static final VersionNumber Lion = new VersionNumber(10,7,0);
/** OSX Mavericks, i.e. 10.9.0 */
public static final VersionNumber Mavericks = new VersionNumber(10,9,0);
}
//
// static initialization order:
//
/** Version 1.6. As a JVM version, it enables certain JVM 1.6 features. */
public static final VersionNumber Version16;
/** Version 1.7. As a JVM version, it enables certain JVM 1.7 features. */
public static final VersionNumber Version17;
public static final String OS;
public static final String OS_lower;
public static final String OS_VERSION;
public static final VersionNumber OS_VERSION_NUMBER;
public static final String ARCH;
public static final String ARCH_lower;
public static final String JAVA_VENDOR;
public static final String JAVA_VENDOR_URL;
public static final String JAVA_VERSION;
public static final VersionNumber JAVA_VERSION_NUMBER;
public static final int JAVA_VERSION_UPDATE;
public static final String JAVA_VM_NAME;
public static final String JAVA_RUNTIME_NAME;
/** True if having {@link java.nio.LongBuffer} and {@link java.nio.DoubleBuffer} available. */
public static final boolean JAVA_SE;
/** True if being compatible w/ language level 6, e.g. JRE 1.6. Implies {@link #JAVA_SE}. Note: We claim Android is compatible. */
public static final boolean JAVA_6;
public static final String NEWLINE;
public static final boolean LITTLE_ENDIAN;
public static final CPUType CPU_ARCH;
public static final ABIType ABI_TYPE;
public static final OSType OS_TYPE;
public static final String os_and_arch;
static {
Version16 = new VersionNumber(1, 6, 0);
Version17 = new VersionNumber(1, 7, 0);
// We don't seem to need an AccessController.doPrivileged() block
// here as these system properties are visible even to unsigned Applets.
OS = System.getProperty("os.name");
OS_lower = OS.toLowerCase();
OS_VERSION = System.getProperty("os.version");
OS_VERSION_NUMBER = new VersionNumber(OS_VERSION);
ARCH = System.getProperty("os.arch");
ARCH_lower = ARCH.toLowerCase();
JAVA_VENDOR = System.getProperty("java.vendor");
JAVA_VENDOR_URL = System.getProperty("java.vendor.url");
JAVA_VERSION = System.getProperty("java.version");
JAVA_VERSION_NUMBER = new VersionNumber(JAVA_VERSION);
{
final int usIdx = JAVA_VERSION.lastIndexOf("_");
int jvmUpdate = 0;
if( usIdx > 0 ) {
final String buildS = Platform.JAVA_VERSION.substring(usIdx+1);
try {
jvmUpdate = Integer.valueOf(buildS);
} catch (NumberFormatException nfe) {}
}
JAVA_VERSION_UPDATE = jvmUpdate;
}
JAVA_VM_NAME = System.getProperty("java.vm.name");
JAVA_RUNTIME_NAME = getJavaRuntimeNameImpl();
JAVA_SE = initIsJavaSE();
JAVA_6 = JAVA_SE && ( AndroidVersion.isAvailable || JAVA_VERSION_NUMBER.compareTo(Version16) >= 0 ) ;
NEWLINE = System.getProperty("line.separator");
LITTLE_ENDIAN = queryIsLittleEndianImpl();
CPU_ARCH = getCPUTypeImpl(ARCH_lower);
OS_TYPE = getOSTypeImpl();
ABI_TYPE = queryABITypeImpl(OS_TYPE, CPU_ARCH);
os_and_arch = getOSAndArch(OS_TYPE, CPU_ARCH, ABI_TYPE);
}
protected PlatformPropsImpl() {}
private static final String getJavaRuntimeNameImpl() {
// the fast path, check property Java SE instead of traversing through the ClassLoader
return AccessController.doPrivileged(new PrivilegedAction() {
@Override
public String run() {
return System.getProperty("java.runtime.name");
}
});
}
private static final boolean initIsJavaSE() {
if( null != JAVA_RUNTIME_NAME && JAVA_RUNTIME_NAME.indexOf("Java SE") != -1) {
return true;
}
// probe for classes we need on a SE environment
try {
Class.forName("java.nio.LongBuffer");
Class.forName("java.nio.DoubleBuffer");
return true;
} catch(ClassNotFoundException ex) {
// continue with Java SE check
}
return false;
}
private static final boolean queryIsLittleEndianImpl() {
ByteBuffer tst_b = Buffers.newDirectByteBuffer(Buffers.SIZEOF_INT); // 32bit in native order
IntBuffer tst_i = tst_b.asIntBuffer();
ShortBuffer tst_s = tst_b.asShortBuffer();
tst_i.put(0, 0x0A0B0C0D);
return 0x0C0D == tst_s.get(0);
}
private static final CPUType getCPUTypeImpl(String archLower) {
if( archLower.equals("x86") ||
archLower.equals("i386") ||
archLower.equals("i486") ||
archLower.equals("i586") ||
archLower.equals("i686") ) {
return CPUType.X86_32;
} else if( archLower.equals("x86_64") ||
archLower.equals("amd64") ) {
return CPUType.X86_64;
} else if( archLower.equals("ia64") ) {
return CPUType.IA64;
} else if( archLower.equals("arm") ) {
return CPUType.ARM;
} else if( archLower.equals("armv5l") ) {
return CPUType.ARMv5;
} else if( archLower.equals("armv6l") ) {
return CPUType.ARMv6;
} else if( archLower.equals("armv7l") ) {
return CPUType.ARMv7;
} else if( archLower.equals("sparc") ) {
return CPUType.SPARC_32;
} else if( archLower.equals("sparcv9") ) {
return CPUType.SPARCV9_64;
} else if( archLower.equals("pa_risc2.0") ) {
return CPUType.PA_RISC2_0;
} else if( archLower.equals("ppc") ) {
return CPUType.PPC;
} else {
throw new RuntimeException("Please port CPU detection to your platform (" + OS_lower + "/" + archLower + ")");
}
}
@SuppressWarnings("unused")
private static final boolean contains(String data, String[] search) {
if(null != data && null != search) {
for(int i=0; i= 0) {
return true;
}
}
}
return false;
}
/**
* Returns the {@link ABIType} of the current platform using given {@link CPUType cpuType}
* and {@link OSType osType} as a hint.
*
* Note the following queries are performed:
*
* - not {@link CPUFamily#ARM} -> {@link ABIType#GENERIC_ABI}
* - else
*
* - {@link OSType#ANDROID} -> {@link ABIType#EABI_GNU_ARMEL} (due to EACCES, Permission denied)
* - else
*
* - Elf ARM Tags -> {@link ABIType#EABI_GNU_ARMEL}, {@link ABIType#EABI_GNU_ARMHF}
* - On Error -> {@link ABIType#EABI_GNU_ARMEL}
*
*
*
*
*
* For Elf parsing either the current executable is used (Linux) or a found java/jvm native library.
*
*
* Elf ARM Tags are read using {@link ElfHeader}, .. and {@link SectionArmAttributes#abiVFPArgsAcceptsVFPVariant(byte)}.
*
* @param osType
* @param cpuType
*
* @return
*/
private static final ABIType queryABITypeImpl(final OSType osType, final CPUType cpuType) {
if( CPUFamily.ARM != cpuType.family ) {
return ABIType.GENERIC_ABI;
}
if( OSType.ANDROID == osType ) { // EACCES (Permission denied) - We assume a not rooted device!
return ABIType.EABI_GNU_ARMEL;
}
return AccessController.doPrivileged(new PrivilegedAction() {
private final String GNU_LINUX_SELF_EXE = "/proc/self/exe";
@Override
public ABIType run() {
boolean abiARM = false;
boolean abiVFPArgsAcceptsVFPVariant = false;
RandomAccessFile in = null;
try {
File file = null;
if( OSType.LINUX == osType ) {
file = new File(GNU_LINUX_SELF_EXE);
if( !checkFileReadAccess(file) ) {
file = null;
}
}
if( null == file ) {
file = findSysLib("java");
}
if( null == file ) {
file = findSysLib("jvm");
}
if( null != file ) {
in = new RandomAccessFile(file, "r");
final ElfHeader eh = ElfHeader.read(in);
if(DEBUG) {
System.err.println("ELF: Got HDR "+GNU_LINUX_SELF_EXE+": "+eh);
}
abiARM = eh.isArm();
if( abiARM ) {
final SectionHeader sh = eh.getSectionHeader(SectionHeader.SHT_ARM_ATTRIBUTES);
if( null != sh ) {
if(DEBUG) {
System.err.println("ELF: Got ARM Attribs Section Header: "+sh);
}
final SectionArmAttributes sArmAttrs = (SectionArmAttributes) sh.readSection(in);
if(DEBUG) {
System.err.println("ELF: Got ARM Attribs Section Block : "+sArmAttrs);
}
final SectionArmAttributes.Attribute abiVFPArgsAttr = sArmAttrs.get(SectionArmAttributes.Tag.ABI_VFP_args);
if( null != abiVFPArgsAttr ) {
abiVFPArgsAcceptsVFPVariant = SectionArmAttributes.abiVFPArgsAcceptsVFPVariant(abiVFPArgsAttr.getULEB128());
}
}
}
}
} catch(Throwable t) {
if(DEBUG) {
t.printStackTrace();
}
} finally {
if(null != in) {
try {
in.close();
} catch (IOException e) { }
}
}
final ABIType res;
if( abiARM ) {
res = abiVFPArgsAcceptsVFPVariant ? ABIType.EABI_GNU_ARMHF : ABIType.EABI_GNU_ARMEL;
} else {
res = ABIType.GENERIC_ABI;
}
if(DEBUG) {
System.err.println("ELF: abiARM "+abiARM+", abiVFPArgsAcceptsVFPVariant "+abiVFPArgsAcceptsVFPVariant+" -> "+res);
}
return res;
} } );
}
private static boolean checkFileReadAccess(File file) {
try {
return file.isFile() && file.canRead();
} catch (Throwable t) { }
return false;
}
private static File findSysLib(String libName) {
ClassLoader cl = PlatformPropsImpl.class.getClassLoader();
final List possibleLibPaths = NativeLibrary.enumerateLibraryPaths(libName, libName, libName, true, cl);
for(int i=0; iplatform property information
*/
public static void initSingleton() { }
/**
* Returns the GlueGen common name for the given OSType and CPUType
* as implemented in the build system in 'gluegen-cpptasks-base.xml'.
*
* A list of currently supported os.and.arch
strings:
*
* - freebsd-i586
* - freebsd-amd64
* - hpux-hppa
* - linux-amd64
* - linux-ia64
* - linux-i586
* - linux-armv6
* - linux-armv6hf
* - android-armv6
* - macosx-universal
* - solaris-sparc
* - solaris-sparcv9
* - solaris-amd64
* - solaris-i586
* - windows-amd64
* - windows-i586
*
* @return
*/
public static final String getOSAndArch(OSType osType, CPUType cpuType, ABIType abiType) {
String _os_and_arch;
switch( cpuType ) {
case X86_32:
_os_and_arch = "i586";
break;
case ARM:
case ARMv5:
case ARMv6:
case ARMv7:
_os_and_arch = "armv6"; // TODO: sync with gluegen-cpptasks-base.xml
break;
case SPARC_32:
_os_and_arch = "sparc";
break;
case PPC:
_os_and_arch = "ppc"; // TODO: sync with gluegen-cpptasks-base.xml
break;
case X86_64:
_os_and_arch = "amd64";
break;
case IA64:
_os_and_arch = "ia64";
break;
case SPARCV9_64:
_os_and_arch = "sparcv9";
break;
case PA_RISC2_0:
_os_and_arch = "risc2.0"; // TODO: sync with gluegen-cpptasks-base.xml
break;
default:
throw new InternalError("Complete case block");
}
if( ABIType.EABI_GNU_ARMHF == abiType ) {
_os_and_arch = _os_and_arch + "hf" ;
}
switch( osType ) {
case ANDROID:
_os_and_arch = "android-" + _os_and_arch;
break;
case MACOS:
_os_and_arch = "macosx-universal";
break;
case WINDOWS:
_os_and_arch = "windows-" + _os_and_arch;
break;
case OPENKODE:
_os_and_arch = "openkode-" + _os_and_arch; // TODO: think about that
break;
case LINUX:
_os_and_arch = "linux-" + _os_and_arch;
break;
case FREEBSD:
_os_and_arch = "freebsd-" + _os_and_arch;
break;
case SUNOS:
_os_and_arch = "solaris-" + _os_and_arch;
break;
case HPUX:
_os_and_arch = "hpux-hppa"; // TODO: really only hppa ?
break;
default:
throw new InternalError("Complete case block");
}
return _os_and_arch;
}
}