如何解决本机库在某些JVM上无法正常工作
我正在尝试使用JNA在Java中使用本机库。库已加载,我可以调用方法,但是在某些JVM发行版中,本机库的行为不符合预期。一些结果:
JDK distributions Behaves as expected
Oracle JDK 1.8.0_191 yes
Liberica JDK 1.8u192 no
Liberica JDK 1.8u275 no
AdoptOpenJDK OpenJ9 1.8u272 yes
AdoptOpenJDK OpenJ9 15.0.1 no
AdoptOpenJDK Hotspot 1.8u275 no
AdoptOpenJDK Hotspot 14.0.1 no
这里的预期行为是通过LC_get_hardware_info
获取硬件信息,然后没有错误地退出。
似乎没有JDK9 +发行版可以工作,某些JDK8发行版可以工作,有些则不能(编辑)所有经过测试的JVM是64位的。
代码(编辑:不调用LC_get_hardware_info
不会改变行为,成功的话就没有输出),SenseLC
返回的值是错误代码:
public static void main(String[] args) {
System.setProperty("jna.library.path",System.getProperty("user.dir"));
SenseLC lib = SenseLC.INSTANCE;
PointerByReference handle = new PointerByReference(new Memory(8));
int ret = lib.LC_open(0,handle);
if (ret != SenseLC.LC_SUCCESS) {
System.out.println("Open: " + SenseLCUtil.getCodeName(ret));
return;
}
System.out.println("Handle: " + handle.getValue());
LC_hardware_info hi = new LC_hardware_info();
ret = lib.LC_get_hardware_info(handle.getValue(),hi);
if (ret != SenseLC.LC_SUCCESS) {
System.out.println("Read: " + SenseLCUtil.getCodeName(ret));
return;
}
System.out.println(hi);
ret = lib.LC_close(handle.getValue());
if (ret != SenseLC.LC_SUCCESS) {
System.out.println("Close: " + SenseLCUtil.getCodeName(ret));
return;
}
}
SenseLCUtil.getCodeName
只是将返回码映射到字符串
预期的行为:
调用SenseLC
后,所有对0
的调用都会返回LC_SUCCESS
(ret = lib.LC_get_hardware_info(handle.getValue(),hi);
),System.out.println(hi);
打印:
LC_hardware_info{
developerNumber={somenumber}
serialNumber={somenumber}
setDate={somenumber}
reservation=0
}
失败行为:
调用int ret = lib.LC_open(0,handle);
成功(调用后ret=0
),然后运行ret = lib.LC_get_hardware_info(handle.getValue(),hi);
ret=3
(LC_INVALID_PARAMETER
)之后,程序输出为:>
Read: LC_INVALID_PARAMETER
似乎某些JDK上的本机代码返回了错误的句柄。
编辑1 :添加了LC_hardware_info和SenseLC类
LC_hardware_info:
@FieldOrder({
"developerNumber","serialNumber","setDate","reservation"
})
public class LC_hardware_info extends Structure {
public int developerNumber;
public byte[] serialNumber = new byte[8];
public int setDate;
public Pointer reservation;
public String getSerial() {
return new String(serialNumber,StandardCharsets.UTF_8);
}
@Override
public String toString() {
return "LC_hardware_info{"
+ "\ndeveloperNumber=" + developerNumber
+ "\nserialNumber=" + getSerial()
+ "\nsetDate=" + setDate
+ "\nreservation=" + reservation
+ "\n}";
}
}
SenseLC:
public interface SenseLC extends Library {
int LC_SUCCESS = 0; // Successful
int LC_OPEN_DEVICE_FAILED = 1; // Open device failed
int LC_FIND_DEVICE_FAILED = 2; // No matching device was found
int LC_INVALID_PARAMETER = 3; // Parameter Error
int LC_INVALID_BLOCK_NUMBER = 4; // Block Error
int LC_HARDWARE_COMMUNICATE_ERROR = 5; // Communication error with hardware
int LC_INVALID_PASSWORD = 6; // Invalid Password
int LC_ACCESS_DENIED = 7; // No privileges
int LC_ALREADY_OPENED = 8; // Device is open
int LC_ALLOCATE_MEMORY_FAILED = 9; // Allocate memory failed
int LC_INVALID_UPDATE_PACKAGE = 10; // Invalid update package
int LC_SYN_ERROR = 11; // thread Synchronization error
int LC_OTHER_ERROR = 12; // Other unknown exceptions
SenseLC INSTANCE = (SenseLC) Native.load("Sense_LC",SenseLC.class);
int LC_open(int vendor,int index,PointerByReference handle);
int LC_close(Pointer handle);
int LC_passwd(Pointer handle,int type,byte[] passwd);
int LC_read(Pointer handle,int block,byte[] buffer);
int LC_write(Pointer handle,byte[] buffer);
int LC_encrypt(Pointer handle,byte[] plaintext,byte[] ciphertext);
int LC_decrypt(Pointer handle,byte[] ciphertext,byte[] plaintext);
int LC_set_passwd(Pointer handle,byte[] passwd,int retries);
int LC_change_passwd(Pointer handle,byte[] oldpasswd,byte[] newpasswd);
int LC_get_hardware_info(Pointer handle,LC_hardware_info info);
int LC_get_software_info(LC_software_info info);
int LC_Hmac(Pointer handle,byte[] text,int textlen,byte[] digest);
int LC_Hmac_software(byte[] text,byte[] key,byte[] digest);
int LC_update(Pointer handle,byte[] buffer);
int LC_set_key(Pointer handle,byte[] key);
int LC_gen_update_pkg(byte[] serial,byte[] buffer,byte[] uptPkg);
}
编辑2 库标题: lc.h,是sdk (Clave2)
的一部分编辑3 : 更新了JNA映射,问题仍然存在。可以找到旧代码here
解决方法
在不同的JVM上获得不同结果的事实表明未定义的行为。在看起来可行的情况下,您会很幸运。
如评论中所述,您的问题很可能是lc_handle_t
的映射。头文件指示在64位计算机上为指针大小,在32位计算机上为int
。因此,当看到PointerByReference
(打开以获取句柄)时,应使用* lc_handle_t
,然后在返回的句柄上使用getValue()
,以用于lc_handle_t
的其他用途。 / p>
该类型还会显示在reservation
结构的LC_hardware_info
字段中,该字段应映射到Pointer
。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。