Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

fix build on w32

  • Loading branch information...
commit a9f90b508ad797e6b5fe7f62687af5ef19f29803 2 parents 7dd96c6 + 0c888d9
@twall authored
View
10 ANDROID.md
@@ -0,0 +1,10 @@
+* Add Android SDK/NDK tools into PATH (used by native/Makefile)
+* Set environment variable NDK_PLATFORM (used by native/Makefile)
+* Build using: ant -Dos.prefix=android-arm dist
+* Tests must be run on the target platform, not the build platform
+* Add dist/jna.jar and/or dist/platform.jar to your application, as needed.
+* If you're using android-maven-plugin, jna.jar can be used as-is (native libraries will be automatically copied into your project).
+* If you're using Google's Eclipse plugin then you must manually remove libjnidispatch.so from jna.jar/lib/armeabi and add it into your project's "libs/armeabi" directory.
+* See http://code.google.com/p/android/issues/detail?id=17861 and http://developer.android.com/guide/practices/jni.html for more information.
+
+
View
4 CHANGES.md
@@ -5,6 +5,10 @@ Features
--------
* `Structure.getFieldOrder()` supersedes `Structure.setFieldOrder()` and is now required - [@twall](https://github.com/twall).
* Search ~/Library/Frameworks and /Library/Frameworks on OSX - [@shaneholloway](https://github.com/shaneholloway).
+* Automatic cleanup of native threads (based on suggestions from neil smith) - [@twall](https://github.com/twall).
+* Add android-arm target (thanks to ochafik for initial work).
+* Add `jna.tmpdir` to override temporary JNA storage location - [@twall](https://github.com/twall).
+* Add EXTRA_MAKE_OPTS ant property to override make variables - [@twall](https://github.com/twall).
Bug Fixes
---------
View
11 README.md
@@ -87,6 +87,17 @@ Primary Documentation (JavaDoc)
The definitive JNA reference is in the [JavaDoc](http://twall.github.com/jna/3.4.1/javadoc/).
+Publishing to maven central
+==========================
+One time: Set up your gpg keys as described here https://docs.sonatype.org/display/Repository/How+To+Generate+PGP+Signatures+With+Maven
+One time: Make sure you have a settings.xml as described at the bottom of 7a1 at https://docs.sonatype.org/display/Repository/Sonatype+OSS+Maven+Repository+Usage+Guide#SonatypeOSSMavenRepositoryUsageGuide-7a.1.POMandsettingsconfig
+
+Every time:
+maybe update version numbers in pom.xml
+ant stage # Uploads current checkout to maven central
+Follow steps from "release it" at https://docs.sonatype.org/display/Repository/Sonatype+OSS+Maven+Repository+Usage+Guide#SonatypeOSSMavenRepositoryUsageGuide-8a.ReleaseIt
+
+
Contributing
============
View
104 build.xml
@@ -9,7 +9,8 @@
support it).
Cross-compile by specifying -Dos.prefix={name-arch} to ant
- (cross-compile currently only configured/tested on w32ce-arm)
+ (cross-compile currently only configured/tested on w32ce-arm and
+ android-arm)
Use -Dskip-native to skip building native parts.
Use -Dheadless to run tests headless
@@ -123,16 +124,26 @@
<condition property="jar.omitted" value="**/*jnidispatch*" else="jnilib-included">
<isset property="omit-jnilib"/>
</condition>
+ <condition property="cross-compile" value="true">
+ <isset property="os.prefix"/>
+ </condition>
+ <!-- Keep cross-compiled natives separate from normal builds -->
+ <condition property="native.subdir" value="native-${os.prefix}" else="native">
+ <isset property="cross-compile"/>
+ </condition>
<condition property="vm.arch" value="-d64" else="">
- <or>
- <equals arg1="${sun.arch.data.model}" arg2="64" trim="true"/>
- <equals arg1="${com.ibm.vm.bitmode}" arg2="64" trim="true"/>
- <os arch="x86_64"/>
- <os arch="amd64"/>
- <os arch="sparcv9"/>
- <os arch="ppc64"/>
- <os arch="ia64"/>
- </or>
+ <and>
+ <not><equals arg1="${os.prefix}" arg2="android-arm" trim="true"/></not>
+ <or>
+ <equals arg1="${sun.arch.data.model}" arg2="64" trim="true"/>
+ <equals arg1="${com.ibm.vm.bitmode}" arg2="64" trim="true"/>
+ <os arch="x86_64"/>
+ <os arch="amd64"/>
+ <os arch="sparcv9"/>
+ <os arch="ppc64"/>
+ <os arch="ia64"/>
+ </or>
+ </and>
</condition>
<condition property="ld.preload" value="LD_PRELOAD_64" else="LD_PRELOAD">
<and>
@@ -195,7 +206,7 @@
<not><equals arg1="${libjsig}" arg2=""/></not>
</condition>
<property name="native.jar" value="${os.prefix}.jar"/>
- <property name="build.native" location="${build}/native"/>
+ <property name="build.native" location="${build}/${native.subdir}"/>
<property name="md5.file" location="${build.native}/jni.checksum"/>
<mkdir dir="${build}"/>
@@ -211,6 +222,8 @@
<echo>java.home=${java.home}</echo>
<echo>java.library.path=${java.library.path}</echo>
<echo>os.prefix=${os.prefix}</echo>
+ <echo>build=${build}</echo>
+ <echo>build.native=${build.native}</echo>
</target>
@@ -251,6 +264,7 @@
<uptodate property="-jar" targetfile="${build}/${jar}">
<srcfiles dir="${classes}">
<patternset id="jar-compiled">
+ <include name="lib/armeabi/*"/>
<include name="com/sun/jna/*"/>
<include name="com/sun/jna/**/*"/>
</patternset>
@@ -488,6 +502,7 @@ osname=macos
<copy file="${lib.native}/out-of-date.jar" tofile="${lib.native}/sunos-amd64.jar" overwrite="true"/>
<copy file="${lib.native}/out-of-date.jar" tofile="${lib.native}/sunos-sparc.jar" overwrite="true"/>
<copy file="${lib.native}/out-of-date.jar" tofile="${lib.native}/sunos-sparcv9.jar" overwrite="true"/>
+ <copy file="${lib.native}/out-of-date.jar" tofile="${lib.native}/android-arm.jar" overwrite="true"/>
<delete failOnError="false" includeEmptyDirs="true">
<fileset dir="${build.native}" includes="*.o,*jnidispatch*"/>
</delete>
@@ -533,12 +548,20 @@ osname=macos
replace="CHECKSUM=${jni.md5} ${comment}"
file="native/Makefile" byline="true"/>
<!-- Handle cross-compilation -->
- <condition property="make.OS" value="OS=w32ce" else="IGNORE=">
+ <condition property="make.OS" value="OS=w32ce">
<equals arg1="${os.prefix}" arg2="w32ce-arm"/>
</condition>
+ <condition property="make.OS" value="OS=android">
+ <equals arg1="${os.prefix}" arg2="android-arm"/>
+ </condition>
+ <property name="make.OS" value="IGNORE="/>
+ <!-- Ensure Makefile ARCH property properly set -->
<condition property="ARCH" value="arm">
<equals arg1="${os.prefix}" arg2="w32ce-arm"/>
</condition>
+ <condition property="ARCH" value="arm">
+ <equals arg1="${os.prefix}" arg2="android-arm"/>
+ </condition>
<condition property="ARCH" value="ppc">
<equals arg1="${os.prefix}" arg2="aix-ppc"/>
</condition>
@@ -559,19 +582,28 @@ osname=macos
</condition>
<condition property="make.SDKROOT"
value="SDKROOT=/Developer/SDKs/MacOSX10.6.sdk">
- <available file="/Developer/SDKs/MacOSX10.6.sdk"/>
+ <and>
+ <equals arg1="${os.prefix}" arg2="darwin" trim="true"/>
+ <available file="/Developer/SDKs/MacOSX10.6.sdk"/>
+ </and>
</condition>
<condition property="make.SDKROOT"
value="SDKROOT=/Developer/SDKs/MacOSX10.5.sdk">
- <available file="/Developer/SDKs/MacOSX10.5.sdk"/>
+ <and>
+ <equals arg1="${os.prefix}" arg2="darwin" trim="true"/>
+ <available file="/Developer/SDKs/MacOSX10.5.sdk"/>
+ </and>
</condition>
<condition property="make.SDKROOT"
value="SDKROOT=/Developer/SDKs/MacOSX10.4u.sdk" else="IGNORE=">
- <available file="/Developer/SDKs/MacOSX10.4u.sdk"/>
+ <and>
+ <equals arg1="${os.prefix}" arg2="darwin" trim="true"/>
+ <available file="/Developer/SDKs/MacOSX10.4u.sdk"/>
+ </and>
</condition>
<!-- Windows' drive letters and spaces in absolute paths wreak havoc on
make -->
- <condition property="make.BUILD" value="BUILD=../${build}/native" else="BUILD=${build.native}">
+ <condition property="make.BUILD" value="BUILD=../${build}/${native.subdir}" else="BUILD=${build.native}">
<os family="windows"/>
</condition>
<condition property="make.PATH" value="PATH=/opt/csw/bin:/usr/sfw/bin:/usr/bin:/usr/ccs/bin" else="IGNORE=">
@@ -591,6 +623,14 @@ osname=macos
<os name="AIX"/>
</or>
</condition>
+ <!-- Allow explicit override of make variables -->
+ <condition property="make.OPTS" value="${EXTRA_MAKE_OPTS}" else="IGNORE=">
+ <isset property="EXTRA_MAKE_OPTS"/>
+ </condition>
+ <!-- Native resource path within jna.jar -->
+ <condition property="native.path" value="lib/armeabi" else="com/sun/jna/${os.prefix}">
+ <equals arg1="${os.prefix}" arg2="android-arm"/>
+ </condition>
<!-- Default make program -->
<property name="make" value="make"/>
@@ -607,16 +647,17 @@ osname=macos
<arg value="${make.ARCH}"/>
<arg value="${make.PATH}"/>
<arg value="${make.OS}"/>
+ <arg line="${make.OPTS}"/>
<arg value="JNA_JNI_VERSION=${jni.version}"/>
<arg value="CHECKSUM=${jni.md5}"/>
</exec>
- <mkdir dir="${classes}/com/sun/jna/${os.prefix}"/>
- <copy todir="${classes}/com/sun/jna/${os.prefix}">
+ <mkdir dir="${classes}/${native.path}"/>
+ <copy todir="${classes}/${native.path}">
<fileset dir="${build.native}"
includes="jnidispatch.dll,libjnidispatch.*"/>
</copy>
- <mkdir dir="${eclipse.classes}/com/sun/jna/${os.prefix}"/>
- <copy todir="${eclipse.classes}/com/sun/jna/${os.prefix}"
+ <mkdir dir="${eclipse.classes}/${native.path}"/>
+ <copy todir="${eclipse.classes}/${native.path}"
failonerror="false">
<fileset dir="${build.native}"
includes="jnidispatch.dll,libjnidispatch.*"/>
@@ -666,8 +707,15 @@ osname=macos
</signjar>
</target>
+ <target name="android-test-setup" depends="compile-tests"
+ description="Configure tests for running on an Android emulator">
+ <!-- 'shared' should be the path to a folder mounted as the mobile
+ device/simulator storage card. -->
+ <property name="shared" value="shared"/>
+ </target>
+
<target name="wince-test-setup" depends="compile-tests"
- description="Configure tests for running on a Windows Mobile device">
+ description="Configure tests for running on the WM emulator">
<!-- 'shared' should be the path to a folder mounted as the mobile
device/simulator storage card. -->
<property name="shared" value="shared"/>
@@ -677,16 +725,16 @@ osname=macos
<zipfileset src="${build}/${testjar}"/>
</jar>
<copy todir="${shared}" file="${build}/${jar}"/>
- <copy todir="${shared}" file="${build}/native/jnidispatch.dll"/>
- <copy todir="${shared}" file="${build}/native/testlib.dll"/>
- <copy todir="${shared}" file="${build}/native/testlib2.dll"/>
+ <copy todir="${shared}" file="${build.native}/jnidispatch.dll"/>
+ <copy todir="${shared}" file="${build.native}/testlib.dll"/>
+ <copy todir="${shared}" file="${build.native}/testlib2.dll"/>
<copy todir="${shared}" file="w32ce-test.lnk"/>
<chmod file="${shared}/*.dll" perm="+x"/>
</target>
<!-- When running tests from an IDE, be sure to set jna.library.path -->
<!-- to where the test library (testlib) is found. -->
- <target name="test" depends="jar,compile-tests"
+ <target name="test" depends="jar,compile-tests" unless="cross-compile"
description="Run all unit tests">
<property name="test.fork" value="yes"/>
<property name="reports.junit" location="${reports}/junit"/>
@@ -838,15 +886,13 @@ osname=macos
<target name="dist" depends="jar,javadoc,contrib-jars,compile-tests,native"
description="Build distribution files">
<copy todir="${dist}">
+ <fileset dir="${build}" includes="${jar}"/>
+ <fileset dir="${contrib}/platform/dist" includes="platform.jar"/>
<fileset dir="${lib.native}">
<include name="*.jar"/>
<exclude name="out-of-date.jar"/>
</fileset>
</copy>
- <copy todir="${dist}">
- <fileset dir="${build}" includes="${jar}"/>
- <fileset dir="${contrib}/platform/dist" includes="platform.jar"/>
- </copy>
<copy todir="${dist}/jnacontrib" flatten="true">
<fileset dir="${contrib}">
<include name="**/build/demo-*.jar" />
View
BIN  dist/android-arm.jar
Binary file not shown
View
BIN  dist/jna.jar
Binary file not shown
View
BIN  lib/native/android-arm.jar
Binary file not shown
View
32 native/Makefile
@@ -16,14 +16,21 @@
# Solaris (i386/amd64/sparc/sparcv9)
# AIX (ppc/ppc64)
# FreeBSD/OpenBSD/NetBSD (i386/amd64)
+# Android (arm)
#
# Built, but with outstanding bugs (not necessarily within JNA):
#
# Linux (ppc64/ia64)
#
# The w32ce build requires cegcc and phoneME for cross-compilation; if these
-# tools are available on the path than "ant -Dos.prefix=w32ce-arm" should
+# tools are available on the path then "ant -Dos.prefix=w32ce-arm" should
# result in a proper build.
+#
+# The android build requires the android SDK+NDK for cross-compilation;
+# make the tools available on the path and compile with
+# "ant -Dos.prefix=android-arm". Put the NDK tools in the path and adjust
+# NDK_PLATFORM below or set it in your environment.
+#
# Systems which support POSIX signals may be able to support VM crash
# protection simply by defining HAVE_PROTECTION. This option has been only
@@ -97,6 +104,25 @@ endif
STRIP=strip -x
# end defaults
+# Android build (cross-compile) requires the android SDK+NDK.
+# Ensure the following tools are in your path and adjust NDK_PLATFORM as needed
+ifeq ($(OS),android)
+CC=arm-linux-androideabi-gcc
+CPP=arm-linux-androideabi-cpp
+LD=arm-linux-androideabi-gcc
+RANLIB=arm-linux-androideabi-ranlib
+STRIP=arm-linux-androideabi-strip -x
+CDEFINES=-DNO_JAWT -DNO_WEAK_GLOBALS -DFFI_MMAP_EXEC_WRIT=1 -DFFI_MMAP_EXEC_SELINUX=0
+COPT+=-fpic -mthumb-interwork -ffunction-sections -funwind-tables -fstack-protector -fno-short-enums -march=armv5te -mtune=xscale -msoft-float
+NDK_PLATFORM?=/Developer/Applications/android-ndk-r7c/platforms/android-14
+JAVA_INCLUDES=
+CINCLUDES+=-I"$(NDK_PLATFORM)/arch-arm/usr/include" # -I/usr/include
+LIBS=-nostdlib -L"$(NDK_PLATFORM)/arch-arm/usr/lib/" -lgcc -lc -ldl -lm
+LDFLAGS+=-Wl,-shared,-Bsymbolic
+FFI_ENV=CPP="$(CPP)" CC="$(CC)" CFLAGS="$(COPT) $(CDEBUG) $(CINCLUDES)" CPPFLAGS="$(CDEFINES) $(CINCLUDES)" LIBS="$(LIBS)" RANLIB="$(RANLIB)"
+FFI_CONFIG=--enable-static --disable-shared --with-pic=yes --host=arm-linux-eabi
+endif
+
# W32CE build requires cegcc cross-compiler and phoneME JavaME implementation
# cegcc: http://sf.net/projects/cegcc
# phoneme: http://davy.preuveneers.net/
@@ -292,7 +318,7 @@ endif
# Unfortunately, we have to use different libffi include files depending on
# the target, so we can't do a simple universal build on darwin. Do
# separate builds, then merge the results.
-$(BUILD)/%.o : %.c dispatch.h $(FFI_LIB)
+$(BUILD)/%.o : %.c dispatch.h protect.h $(FFI_LIB)
@mkdir -p $(BUILD)
ifneq ($(SDKROOT),)
$(CC) -arch $(ARCH) $(CFLAGS) -c $< -o $@.$(ARCH)
@@ -330,7 +356,7 @@ else
TESTDEP=$(TESTLIB)
endif
$(TESTLIB2): $(BUILD)/testlib2.o
- $(LD) $(LDFLAGS) $< $(TESTDEP)
+ $(LD) $(LDFLAGS) $< $(TESTDEP) $(LIBS)
ifneq ($(DYNAMIC_LIBFFI),true)
$(FFI_LIB):
View
92 native/callback.c
@@ -12,6 +12,7 @@
* Lesser General Public License for more details.
*/
+#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
@@ -188,6 +189,7 @@ create_callback(JNIEnv* env, jobject obj, jobject method,
if (calling_convention == CALLCONV_STDCALL) {
abi = FFI_STDCALL;
}
+ // Calling into Java on win32 *always* uses stdcall
java_abi = FFI_STDCALL;
#endif // _WIN32
@@ -216,16 +218,17 @@ create_callback(JNIEnv* env, jobject obj, jobject method,
rtype = '*';
}
switch(rtype) {
- case 'V': cb->fptr = (*env)->CallVoidMethod; break;
- case 'Z': cb->fptr = (*env)->CallBooleanMethod; break;
- case 'B': cb->fptr = (*env)->CallByteMethod; break;
- case 'S': cb->fptr = (*env)->CallShortMethod; break;
- case 'C': cb->fptr = (*env)->CallCharMethod; break;
- case 'I': cb->fptr = (*env)->CallIntMethod; break;
- case 'J': cb->fptr = (*env)->CallLongMethod; break;
- case 'F': cb->fptr = (*env)->CallFloatMethod; break;
- case 'D': cb->fptr = (*env)->CallDoubleMethod; break;
- default: cb->fptr = (*env)->CallObjectMethod; break;
+#define OFFSETOF(ENV,METHOD) ((size_t)((char *)&(*(ENV))->METHOD - (char *)(*(ENV))))
+ case 'V': cb->fptr_offset = OFFSETOF(env, CallVoidMethod); break;
+ case 'Z': cb->fptr_offset = OFFSETOF(env, CallBooleanMethod); break;
+ case 'B': cb->fptr_offset = OFFSETOF(env, CallByteMethod); break;
+ case 'S': cb->fptr_offset = OFFSETOF(env, CallShortMethod); break;
+ case 'C': cb->fptr_offset = OFFSETOF(env, CallCharMethod); break;
+ case 'I': cb->fptr_offset = OFFSETOF(env, CallIntMethod); break;
+ case 'J': cb->fptr_offset = OFFSETOF(env, CallLongMethod); break;
+ case 'F': cb->fptr_offset = OFFSETOF(env, CallFloatMethod); break;
+ case 'D': cb->fptr_offset = OFFSETOF(env, CallDoubleMethod); break;
+ default: cb->fptr_offset = OFFSETOF(env, CallObjectMethod); break;
}
status = ffi_prep_cif(&cb->java_cif, java_abi, argc+3, java_ffi_rtype, cb->java_arg_types);
if (!ffi_error(env, "callback setup (2)", status)) {
@@ -384,7 +387,9 @@ callback_invoke(JNIEnv* env, callback *cb, ffi_cif* cif, void *resp, void **cbar
else if (cb->cif.rtype->size > cif->rtype->size) {
resp = alloca(cb->cif.rtype->size);
}
- ffi_call(&cb->java_cif, FFI_FN(cb->fptr), resp, args);
+#define FPTR(ENV,OFFSET) (*(void **)((char *)(*(ENV)) + OFFSET))
+#define JNI_FN(X) ((void (JNICALL *)(void))(X))
+ ffi_call(&cb->java_cif, JNI_FN(FPTR(env, cb->fptr_offset)), resp, args);
if ((*env)->ExceptionCheck(env)) {
jthrowable throwable = (*env)->ExceptionOccurred(env);
(*env)->ExceptionClear(env);
@@ -466,6 +471,67 @@ callback_invoke(JNIEnv* env, callback *cb, ffi_cif* cif, void *resp, void **cbar
}
}
+// Handle automatic thread cleanup
+static void detach_thread(void* data) {
+ if (data != NULL) {
+ JavaVM* jvm = (JavaVM *)data;
+ (*jvm)->DetachCurrentThread(jvm);
+ }
+}
+
+#ifdef _WIN32
+
+static DWORD dwTlsIndex;
+BOOL WINAPI DllMain(HINSTANCE hDLL, DWORD fdwReason, LPVOID lpvReserved) {
+ switch (fdwReason) {
+ case DLL_PROCESS_ATTACH:
+ dwTlsIndex = TlsAlloc();
+ if (dwTlsIndex == TLS_OUT_OF_INDEXES) {
+ return FALSE;
+ }
+ break;
+ case DLL_PROCESS_DETACH:
+ TlsFree(dwTlsIndex);
+ break;
+ case DLL_THREAD_ATTACH:
+ break;
+ case DLL_THREAD_DETACH: {
+ detach_thread(TlsGetValue(dwTlsIndex));
+ break;
+ }
+ default:
+ break;
+ }
+ return TRUE;
+}
+
+#else
+
+#include <pthread.h>
+
+static pthread_key_t key;
+static void make_key() {
+ pthread_key_create(&key, detach_thread);
+}
+
+#endif
+
+/** Set up to detach the thread when it exits, or clear any handlers if the
+ argument is NULL.
+*/
+static void
+jvm_detach_on_exit(JavaVM* jvm) {
+#ifdef _WIN32
+ TlsSetValue(dwTlsIndex, jvm);
+#else
+ static pthread_once_t key_once = PTHREAD_ONCE_INIT;
+ pthread_once(&key_once, make_key);
+ if (!jvm || pthread_getspecific(key) == NULL) {
+ pthread_setspecific(key, jvm);
+ }
+#endif
+}
+
static void
callback_dispatch(ffi_cif* cif, void* resp, void** cbargs, void* user_data) {
callback* cb = ((callback *)user_data);
@@ -528,6 +594,10 @@ callback_dispatch(ffi_cif* cif, void* resp, void** cbargs, void* user_data) {
if (detach) {
(*jvm)->DetachCurrentThread(jvm);
+ jvm_detach_on_exit(NULL);
+ }
+ else if (!was_attached) {
+ jvm_detach_on_exit(jvm);
}
}
View
9 native/dispatch.c
@@ -2,7 +2,7 @@
* @(#)dispatch.c 1.9 98/03/22
*
* Copyright (c) 1998 Sun Microsystems, Inc. All Rights Reserved.
- * Copyright (c) 2007-2011 Timothy Wall. All Rights Reserved.
+ * Copyright (c) 2007-2012 Timothy Wall. All Rights Reserved.
* Copyright (c) 2007 Wayne Meissner. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
@@ -16,11 +16,6 @@
* Lesser General Public License for more details.
*/
-/*
- * JNI native methods supporting the infrastructure for shared
- * dispatchers.
- */
-
#if defined(_WIN32)
#ifdef _MSC_VER
#pragma warning( disable : 4201 ) /* nameless struct/union (jni_md.h) */
@@ -2989,8 +2984,8 @@ Java_com_sun_jna_Native_getPreserveLastError(JNIEnv *UNUSED(env), jclass UNUSED(
JNIEXPORT void JNICALL
Java_com_sun_jna_Native_setLastError(JNIEnv *env, jclass UNUSED(classp), jint code) {
- SET_LAST_ERROR(code);
update_last_error(env, code);
+ SET_LAST_ERROR(code);
}
JNIEXPORT jstring JNICALL
View
16 native/dispatch.h
@@ -110,7 +110,7 @@ typedef struct _callback {
jmethodID methodID;
char* arg_jtypes;
jboolean direct;
- void* fptr;
+ size_t fptr_offset;
void* saved_x_closure;
} callback;
@@ -204,6 +204,20 @@ extern jobject initializeThread(callback*,AttachOptions*);
extern int lastError();
extern void setLastError(int err);
+#ifdef NO_WEAK_GLOBALS
+#define NewWeakGlobalRef NewGlobalRef
+#define DeleteWeakGlobalRef DeleteGlobalRef
+#endif
+
+/* Native memory fault protection */
+#ifdef HAVE_PROTECTION
+#define PROTECT is_protected()
+#endif
+#include "protect.h"
+#define ON_ERROR() throwByName(env, EError, "Invalid memory access")
+#define PSTART() PROTECTED_START()
+#define PEND() PROTECTED_END(ON_ERROR())
+
#ifdef __cplusplus
}
#endif
View
3  native/testlib.c
@@ -45,6 +45,7 @@ typedef __int64 int64_t;
#define THREAD_EXIT() ExitThread(0)
#define THREAD_FUNC(FN,ARG) DWORD WINAPI FN(LPVOID ARG)
#define THREAD_CURRENT() GetCurrentThreadId()
+#define THREAD_RETURN return 0
#else
#define EXPORT
#include <unistd.h>
@@ -54,6 +55,7 @@ typedef __int64 int64_t;
#define THREAD_CREATE(TP, FN, DATA) pthread_create(TP, NULL, FN, DATA)
#define THREAD_EXIT() pthread_exit(NULL)
#define THREAD_FUNC(FN,ARG) void* FN(void *ARG)
+#define THREAD_RETURN return NULL
#define THREAD_CURRENT() pthread_self()
#endif
@@ -645,6 +647,7 @@ static THREAD_FUNC(thread_function, arg) {
SLEEP(td.sleep_time);
}
THREAD_EXIT();
+ THREAD_RETURN;
}
static thread_data data;
View
44 src/com/sun/jna/Native.java
@@ -591,9 +591,16 @@ else if ("powerpc64".equals(arch)) {
arch = "ppc64";
}
switch(osType) {
+ case Platform.ANDROID:
+ if (arch.startsWith("arm")) {
+ arch = "arm";
+ }
+ osPrefix = "android-" + arch;
+ break;
case Platform.WINDOWS:
- if ("i386".equals(arch))
+ if ("i386".equals(arch)) {
arch = "x86";
+ }
osPrefix = "win32-" + arch;
break;
case Platform.WINDOWSCE:
@@ -682,6 +689,10 @@ private static void loadNativeLibrary() {
}
}
}
+ if (Platform.isAndroid()) {
+ // Native libraries on android must be bundled with the APK
+ System.setProperty("jna.nounpack", "true");
+ }
try {
if (!Boolean.getBoolean("jna.nosys")) {
System.loadLibrary(libName);
@@ -720,7 +731,7 @@ private static void loadNativeLibraryFromJar() {
url = Native.class.getResource(resourceName);
}
if (url == null) {
- throw new UnsatisfiedLinkError("jnidispatch (" + resourceName
+ throw new UnsatisfiedLinkError("JNA native support (" + resourceName
+ ") not found in resource path");
}
@@ -814,6 +825,8 @@ public static int getLastError() {
public static native void setLastError(int code);
/** Update the last error value (called from native code). */
+ // This has to be called immediately after a native call to ensure that
+ // subsequent VM operations don't overwrite the last error value
static void updateLastError(int e) {
lastError.set(new Integer(e));
}
@@ -906,11 +919,30 @@ static void markTemporaryFile(File file) {
catch(IOException e) { e.printStackTrace(); }
}
+ /** Obtain a directory suitable for writing JNA-specific temporary files.
+ Override with <code>jna.tmpdir</code>
+ */
static File getTempDir() {
- File tmp = new File(System.getProperty("java.io.tmpdir"));
- File jnatmp = new File(tmp, "jna-" + System.getProperty("user.name"));
- jnatmp.mkdirs();
- return jnatmp.exists() ? jnatmp : tmp;
+ File jnatmp;
+ String prop = System.getProperty("jna.tmpdir");
+ if (prop != null) {
+ jnatmp = new File(prop);
+ }
+ else {
+ File tmp = new File(System.getProperty("java.io.tmpdir"));
+ jnatmp = new File(tmp, "jna-" + System.getProperty("user.name"));
+ jnatmp.mkdirs();
+ if (!jnatmp.exists() || !jnatmp.canWrite()) {
+ jnatmp = tmp;
+ }
+ }
+ if (!jnatmp.exists()) {
+ throw new Error("JNA temporary directory " + jnatmp + " does not exist");
+ }
+ if (!jnatmp.canWrite()) {
+ throw new Error("JNA temporary directory " + jnatmp + " is not writable");
+ }
+ return jnatmp;
}
/** Remove all marked temporary files in the given directory. */
View
12 src/com/sun/jna/NativeLibrary.java
@@ -141,7 +141,17 @@ private static NativeLibrary loadLibrary(String libraryName, Map options) {
}
}
catch(UnsatisfiedLinkError e) {
- if (Platform.isLinux()) {
+ // For android, try to "preload" the library using
+ // System.loadLibrary(), which looks into the private /data/data
+ // path, not found in any properties
+ if (Platform.isAndroid()) {
+ try {
+ System.loadLibrary(libraryName);
+ handle = Native.open(libraryPath);
+ }
+ catch(UnsatisfiedLinkError e2) { e = e2; }
+ }
+ else if (Platform.isLinux()) {
//
// Failed to load the library normally - try to match libfoo.so.*
//
View
27 src/com/sun/jna/Platform.java
@@ -20,6 +20,7 @@
public static final int OPENBSD = 5;
public static final int WINDOWSCE = 6;
public static final int AIX = 7;
+ public static final int ANDROID = 8;
/** Whether read-only (final) fields within Structures are supported. */
public static final boolean RO_FIELDS;
@@ -39,7 +40,12 @@
static {
String osName = System.getProperty("os.name");
if (osName.startsWith("Linux")) {
- osType = LINUX;
+ if ("dalvik".equals(System.getProperty("java.vm.name").toLowerCase())) {
+ osType = ANDROID;
+ }
+ else {
+ osType = LINUX;
+ }
}
else if (osName.startsWith("AIX")) {
osType = AIX;
@@ -93,6 +99,9 @@ public static final int getOSType() {
public static final boolean isMac() {
return osType == MAC;
}
+ public static final boolean isAndroid() {
+ return osType == ANDROID;
+ }
public static final boolean isLinux() {
return osType == LINUX;
}
@@ -149,9 +158,8 @@ public static final boolean isIntel() {
|| arch.equals("x86_64")
|| arch.equals("amd64")) {
return true;
- } else {
- return false;
- }
+ }
+ return false;
}
public static final boolean isPPC() {
@@ -162,18 +170,13 @@ public static final boolean isPPC() {
|| arch.equals("powerpc")
|| arch.equals("powerpc64")) {
return true;
- } else {
- return false;
- }
+ }
+ return false;
}
public static final boolean isARM() {
String arch =
System.getProperty("os.arch").toLowerCase().trim();
- if (arch.equals("arm")) {
- return true;
- } else {
- return false;
- }
+ return arch.startsWith("arm");
}
}
View
9 src/com/sun/jna/Structure.java
@@ -109,7 +109,7 @@
String arch = System.getProperty("os.arch").toLowerCase();
isPPC = "ppc".equals(arch) || "powerpc".equals(arch);
isSPARC = "sparc".equals(arch);
- isARM = "arm".equals(arch);
+ isARM = arch.startsWith("arm");
}
/** Use the platform default alignment. */
@@ -129,7 +129,10 @@
//public static final int ALIGN_8 = 6;
static final int MAX_GNUC_ALIGNMENT =
- isSPARC || ((isPPC || isARM) && Platform.isLinux()) || Platform.isAix()
+ isSPARC
+ || ((isPPC || isARM)
+ && (Platform.isLinux() || Platform.isAndroid()))
+ || Platform.isAix()
? 8 : Native.LONG_SIZE;
protected static final int CALCULATE_SIZE = -1;
static final Map layoutInfo = new WeakHashMap();
@@ -836,7 +839,7 @@ private List sort(Collection c) {
}
/** Returns all field names (sorted) provided so far by
- {@link #setFieldOrder}
+ {@link #getFieldOrder}
@param force set if results are required immediately
@return null if not yet able to provide fields, and force is false.
@throws Error if force is true and field order data not yet specified
View
34 test/com/sun/jna/CallbacksTest.java
@@ -1032,13 +1032,39 @@ public void callback() {
};
callThreadedCallback(cb, init, COUNT, 100, called);
- assertEquals("Native thread mapping not preserved: " + threads,
+ assertEquals("Multiple callbacks on a given native thread should use the same Thread mapping: " + threads,
1, threads.size());
}
- // Callback indicates detach preference; thread is non-daemon (default),
+ public void testAttachedThreadCleanupOnExit() throws Exception {
+ final Set threads = new HashSet();
+ final int[] called = { 0 };
+ TestLibrary.VoidCallback cb = new TestLibrary.VoidCallback() {
+ public void callback() {
+ threads.add(new WeakReference(Thread.currentThread()));
+ ++called[0];
+ Native.detach(false);
+ }
+ };
+ callThreadedCallback(cb, null, 1, 0, called);
+ while (threads.size() == 0) {
+ Thread.sleep(10);
+ }
+ long start = System.currentTimeMillis();
+ WeakReference ref = (WeakReference)threads.iterator().next();
+ while (ref.get() != null) {
+ System.gc();
+ Thread.sleep(10);
+ if (System.currentTimeMillis() - start > 5000) {
+ fail("Timed out waiting for attached thread to be detached on exit and disposed: " + ref.get());
+ }
+ }
+ }
+
+ // Callback indicates detach preference (instead of
+ // CallbackThreadInitializer); thread is non-daemon (default),
// but callback explicitly detaches it on final invocation.
- public void testDynamicCallbackThreadPersistence() throws Exception {
+ public void testCallbackIndicatedThreadDetach() throws Exception {
final int[] called = {0};
final Set threads = new HashSet();
final int COUNT = 5;
@@ -1058,7 +1084,7 @@ else if (count == COUNT) {
};
callThreadedCallback(cb, null, COUNT, 100, called);
- assertEquals("Native thread mapping not preserved: " + threads,
+ assertEquals("Multiple callbacks in the same native thread should use the same Thread mapping: " + threads,
1, threads.size());
Thread thread = (Thread)threads.iterator().next();
long start = System.currentTimeMillis();
View
4 test/com/sun/jna/NativeLibraryTest.java
@@ -185,7 +185,11 @@ public void testParseVersion() throws Exception {
}
}
+ // XFAIL on android
public void testGetProcess() {
+ if (Platform.isAndroid()) {
+ fail("dlopen(NULL) segfaults on Android");
+ }
NativeLibrary process = NativeLibrary.getProcess();
// Access a common C library function
process.getFunction("printf");
View
4 test/com/sun/jna/NativeTest.java
@@ -281,6 +281,10 @@ public void testOSPrefix() {
assertEquals("Wrong resource path FreeBSD/x86", "/com/sun/jna/freebsd-i386",
Native.getNativeLibraryResourcePath(Platform.FREEBSD,
"x86", "FreeBSD"));
+ assertEquals("Wrong resource path Linux/armv7l (android)", "/com/sun/jna/android-arm",
+ Native.getNativeLibraryResourcePath(Platform.ANDROID,
+ "armv7l", "Linux"));
+
assertEquals("Wrong resource path other/other", "/com/sun/jna/name-ppc",
Native.getNativeLibraryResourcePath(Platform.UNSPECIFIED,
"PowerPC", "Name Of System"));
View
2  test/com/sun/jna/ReturnTypesTest.java
@@ -43,7 +43,6 @@ protected List getFieldOrder() {
public static class TestSmallStructure extends Structure {
public static class ByValue extends TestSmallStructure implements Structure.ByValue { }
-
public byte c1;
public byte c2;
public short s;
@@ -54,7 +53,6 @@ protected List getFieldOrder() {
public static class TestStructure extends Structure {
public static class ByValue extends TestStructure implements Structure.ByValue { }
-
public byte c;
public short s;
public int i;
View
1  test/com/sun/jna/StructureTest.java
@@ -1521,7 +1521,6 @@ public TestByReferenceArrayField(Pointer m) {
super(m);
read(); // Important!
}
-
public int value1;
public ByReference[] array = new ByReference[13];
public int value2;
Please sign in to comment.
Something went wrong with that request. Please try again.