我正在开发一个小应用程序,应该使用数字签名和退出来签署文档。 签名可以在PKCS#12存档(.pfx文件)中或在智能卡设备上。
使用pfx文件很简单,工作正常。
但是,有时使用智能卡设备,该过程会在Windows 8 PC上挂起。
文档已正确签名,但该过程未终止。它只是挂起。
我正在使用Sun的PKCS#11提供商 - sun.security.pkcs11.SunPKCS11
基本上我这样做:
SunPKCS11 provider = new SunPKCS11(configuration);
Security.addProvider(provider);
..... some work .....
provider.logout()
Security.removeProvider(provider);
现在......即使我在System.exit(0)
方法的末尾调用main
或抛出异常,我也可以看到输出中的堆栈跟踪,但进程并未终止。
我已经添加了一个关闭钩子来查看它是否已被执行,即JVM正试图停止。
很少发生这种情况,仅在Windows 8 PC上发生。尝试使用不同的智能卡,只有使用cmp11.dll
的卡(dll由智能卡供应商提供)才会发生。
使用相同的dll与智能卡进行通信,但在Windows 7,XP或某些Windows 8 PC上运行良好
在x86或x64 Windows 8上使用Java 8,Update 45运行它
尝试获取线程转储以查看挂起的内容:
public static void main(String[] args) {
// do my job, register provider, sign documents, remove provider ...
for(int i = 0; i < 20; ++i) {
System.err.println("Sleep... " + i);
Thread.sleep(2 * 1000);
}
System.err.println("Exiting...");
}
如果我在打印jstack -l 3232 > dump.log 2>&1
时执行Sleep... x
,则一切正常。
但是,如果我在打印jstack -F -l 3232 > dump2.log 2>&1
并且应用程序挂起(使用Exiting...
因为进程挂起)时执行-F
,则会收到以下信息:
Attaching to process ID 3232, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.45-b02
Deadlock Detection:
No deadlocks found.
Thread Exception in thread "main"
java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at sun.tools.jstack.JStack.runJStackTool(JStack.java:140)
at sun.tools.jstack.JStack.main(JStack.java:106)
Caused by: sun.jvm.hotspot.debugger.DebuggerException: Windbg Error: GetThreadIdBySystemId failed!
at sun.jvm.hotspot.debugger.windbg.WindbgDebuggerLocal.getThreadIdFromSysId0(Native Method)
at sun.jvm.hotspot.debugger.windbg.WindbgDebuggerLocal.getThreadIdFromSysId(WindbgDebuggerLocal.java:284)
at sun.jvm.hotspot.debugger.windbg.amd64.WindbgAMD64Thread.getThreadID(WindbgAMD64Thread.java:88)
at sun.jvm.hotspot.debugger.windbg.amd64.WindbgAMD64Thread.toString(WindbgAMD64Thread.java:81)
at java.lang.String.valueOf(String.java:2982)
at java.io.PrintStream.print(PrintStream.java:683)
at sun.jvm.hotspot.runtime.win32_amd64.Win32AMD64JavaThreadPDAccess.printThreadIDOn(Win32AMD64JavaThreadPDAccess.java:114)
at sun.jvm.hotspot.runtime.JavaThread.printThreadIDOn(JavaThread.java:265)
at sun.jvm.hotspot.tools.StackTrace.run(StackTrace.java:79)
at sun.jvm.hotspot.tools.StackTrace.run(StackTrace.java:45)
at sun.jvm.hotspot.tools.JStack.run(JStack.java:66)
at sun.jvm.hotspot.tools.Tool.startInternal(Tool.java:260)
at sun.jvm.hotspot.tools.Tool.start(Tool.java:223)
at sun.jvm.hotspot.tools.Tool.execute(Tool.java:118)
at sun.jvm.hotspot.tools.JStack.main(JStack.java:92)
... 6 more
我可以在任务管理器中看到PID 3232的过程!
知道为什么它没有终止或为什么jstack
会失败?
修改
好的,尝试在单独的流程中提取签名,使用Runtime.exec
执行签名,然后使用Process.destroy
将其删除但是......似乎没有帮助。子进程仍然留在任务管理器中。
Aaaaand ......现在我别无选择,只能让它自杀;(
try {
String name = java.lang.management.ManagementFactory.getRuntimeMXBean().getName();
Runtime.getRuntime().exec("taskkill.exe /F /PID " + name.split("@")[0]);
}
catch(Throwable t) {
Runtime.getRuntime().exec("taskkill.exe /F /IM java.exe");
}
编辑2
也尝试Runtime.halt
。仍然没有终止这个过程...
我很感激任何想法!
答案 0 :(得分:1)
这不会解决您的根本原因,但此方法可用于强制JVM终止:
http://docs.oracle.com/javase/7/docs/api/java/lang/Runtime.html#halt(int)
正如Javadoc所说,请谨慎使用; - )
答案 1 :(得分:1)
我在Windows 8 PC上遇到sun.security.pkcs11.SunPKCS11的问题。这对我有用:
Runtime.getRuntime().exec("taskkill.exe /F /PID " + name.split("@")[0]);
Thread.sleep(500);