1616
1717package io .objectbox .internal ;
1818
19+ import io .objectbox .BoxStore ;
1920import org .greenrobot .essentials .io .IoUtils ;
2021
22+ import javax .annotation .Nullable ;
2123import java .io .BufferedInputStream ;
2224import java .io .BufferedOutputStream ;
25+ import java .io .BufferedReader ;
2326import java .io .File ;
2427import java .io .FileOutputStream ;
2528import java .io .IOException ;
2629import java .io .InputStream ;
30+ import java .io .InputStreamReader ;
2731import java .io .OutputStream ;
2832import java .lang .reflect .InvocationTargetException ;
2933import java .lang .reflect .Method ;
3034import java .net .URL ;
3135import java .net .URLConnection ;
3236
33- import io .objectbox .BoxStore ;
34-
3537/**
3638 * Separate class, so we can mock BoxStore.
3739 */
@@ -103,13 +105,21 @@ public class NativeLibraryLoader {
103105 String osArch = System .getProperty ("os.arch" );
104106 String sunArch = System .getProperty ("sun.arch.data.model" );
105107 String message = String .format (
106- "Loading ObjectBox native library failed: vendor=%s,os=%s,os.arch=%s,sun.arch=%s,android=%s,linux=%s" ,
107- vendor , osName , osArch , sunArch , android , isLinux
108+ "[ObjectBox] Loading native library failed, please report this to us: " +
109+ "vendor=%s,os=%s,os.arch=%s,model=%s,android=%s,linux=%s,machine=%s" ,
110+ vendor , osName , osArch , sunArch , android , isLinux , getCpuArchOSOrNull ()
108111 );
109112 throw new LinkageError (message , e ); // UnsatisfiedLinkError does not allow a cause; use its super class
110113 }
111114 }
112115
116+ /**
117+ * Get CPU architecture of the JVM (Note: this can not be used for Android, Android decides arch on its own
118+ * and looks for library in appropriately named folder).
119+ * <p>
120+ * Note that this may not be the architecture of the actual hardware
121+ * (e.g. when running a x86 JVM on an amd64 machine).
122+ */
113123 private static String getCpuArch () {
114124 String osArch = System .getProperty ("os.arch" );
115125 String cpuArch = null ;
@@ -119,34 +129,70 @@ private static String getCpuArch() {
119129 cpuArch = "x64" ;
120130 } else if (osArch .equalsIgnoreCase ("x86" )) {
121131 cpuArch = "x86" ;
132+ } else if ("aarch64" .equals (osArch ) || osArch .startsWith ("armv8" ) || osArch .startsWith ("arm64" )) {
133+ // 64-bit ARM
134+ cpuArch = "arm64" ;
122135 } else if (osArch .startsWith ("arm" )) {
123- switch (osArch ) {
124- case "armv7" :
125- case "armv7l" :
126- case "armeabi-v7a" : // os.arch "armeabi-v7a" might be Android only, but let's try anyway...
127- cpuArch = "armv7" ;
128- break ;
129- case "arm64-v8a" :
130- cpuArch = "arm64" ;
131- break ;
132- case "armv6" :
133- cpuArch = "armv6" ;
134- break ;
135- default :
136- cpuArch = "armv6" ; // Lowest version we support
137- System .err .println ("Unknown os.arch \" " + osArch + "\" - ObjectBox is defaulting to " + cpuArch );
138- break ;
136+ // 32-bit ARM
137+ if (osArch .startsWith ("armv7" ) || osArch .startsWith ("armeabi-v7" )) {
138+ cpuArch = "armv7" ;
139+ } else if (osArch .startsWith ("armv6" )) {
140+ cpuArch = "armv6" ;
141+ } else if ("arm" .equals (osArch )) {
142+ // JVM may just report "arm" for any 32-bit ARM, so try to check with OS.
143+ String cpuArchOSOrNull = getCpuArchOSOrNull ();
144+ if (cpuArchOSOrNull != null ) {
145+ String cpuArchOS = cpuArchOSOrNull .toLowerCase ();
146+ if (cpuArchOS .startsWith ("armv7" )) {
147+ cpuArch = "armv7" ;
148+ } else if (cpuArchOS .startsWith ("armv6" )){
149+ cpuArch = "armv6" ;
150+ } // else use fall back below.
151+ } // else use fall back below.
152+ }
153+ if (cpuArch == null ) {
154+ // Fall back to lowest supported 32-bit ARM version.
155+ cpuArch = "armv6" ;
156+ System .err .printf ("[ObjectBox] 32-bit ARM os.arch unknown (will use %s), " +
157+ "please report this to us: os.arch=%s, machine=%s%n" ,
158+ cpuArch , osArch , getCpuArchOSOrNull ());
139159 }
140160 }
141161 }
162+ // If os.arch is not covered above try a x86 version based on JVM bit-ness.
142163 if (cpuArch == null ) {
143164 String sunArch = System .getProperty ("sun.arch.data.model" );
144- cpuArch = "32" .equals (sunArch ) ? "x86" : "x64" ;
145- System .err .println ("Unknown os.arch \" " + osArch + "\" - ObjectBox is defaulting to " + cpuArch );
165+ if ("64" .equals (sunArch )) {
166+ cpuArch = "x64" ;
167+ } else if ("32" .equals (sunArch )) {
168+ cpuArch = "x86" ;
169+ } else {
170+ cpuArch = "unknown" ;
171+ }
172+ System .err .printf ("[ObjectBox] os.arch unknown (will use %s), " +
173+ "please report this to us: os.arch=%s, model=%s, machine=%s%n" ,
174+ cpuArch , osArch , sunArch , getCpuArchOSOrNull ());
146175 }
147176 return cpuArch ;
148177 }
149178
179+ /**
180+ * Get architecture using operating system tools. Currently only Linux is supported (using uname).
181+ */
182+ @ Nullable
183+ private static String getCpuArchOSOrNull () {
184+ String archOrNull = null ;
185+ try {
186+ // Linux
187+ Process exec = Runtime .getRuntime ().exec ("uname -m" );
188+ BufferedReader reader = new BufferedReader (new InputStreamReader (exec .getInputStream ()));
189+ archOrNull = reader .readLine ();
190+ reader .close ();
191+ } catch (Exception ignored ) {
192+ }
193+ return archOrNull ;
194+ }
195+
150196 private static void checkUnpackLib (String filename ) {
151197 String path = "/native/" + filename ;
152198 URL resource = NativeLibraryLoader .class .getResource (path );
0 commit comments