使用JAVA智能卡API读取NFC标签不适用于MAC OS [英] Reading NFC Tag using JAVA Smart Card API not working on MAC OS

查看:275
本文介绍了使用JAVA智能卡API读取NFC标签不适用于MAC OS的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在开发一个应用程序,用于从NFC读取器(ACR122U-A9)设备读取NFC标签UID。
我使用JAVA和javax.smartcardio API来检测NFC阅读器和阅读NFC标签。

I am developing an application to read a NFC Tag UID from NFC Reader (ACR122U-A9) device. I used JAVA and javax.smartcardio API to detect the NFC Reader and Reading NFC Tag.

应用程序的功能是在NFC阅读器时显示通知设备与PC连接或断开连接。然后,如果设备已连接且显示NFC标签,则显示NFC标签显示的通知。
我试图找到基于事件的api来实现上述功能,但我找不到所以我使用Java Timer和Polling来获取NFC读卡器设备和NFC标签。

The functionality of the application is to display notification when the NFC Reader device is connect or disconnect from PC. Then if the device is connected and NFC Tag is presented then display the notification that NFC Tag is presented. I tried to find the Event based api to implement above functionality but I cannot find so I used Java Timer and Polling for the NFC Reader Device and NFC Tag.

以下是我的示例JAVA代码,用于轮询NFC设备和标签。

Following is my sample JAVA code that used for Polling for NFC device and Tag.

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.smartcardio.CardTerminal;
import javax.smartcardio.TerminalFactory;

/**
 *
 * @author sa
 */
public class NFC_Test {

    /**
     * @param args the command line arguments
     */
    static Timer timer;

    public static void main(String[] args) {

        try {


            timer = new Timer();  //At this line a new Thread will be created

            timer.scheduleAtFixedRate(new NFC_Test.MyTask(), 0, 1000);


        } catch (Exception ex) {
            Logger.getLogger(NFC_Test.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    static class MyTask extends TimerTask {

        public void run() {


    ///////////////////This fix applied after reading thread at http://stackoverflow.com/a/16987873/1411888
            try {
                Class pcscterminal =
                        Class.forName("sun.security.smartcardio.PCSCTerminals");
                Field contextId = pcscterminal.getDeclaredField("contextId");
                contextId.setAccessible(true);

                if (contextId.getLong(pcscterminal) != 0L) {
                    Class pcsc =
                            Class.forName("sun.security.smartcardio.PCSC");

                    Method SCardEstablishContext = pcsc.getDeclaredMethod(
                            "SCardEstablishContext", new Class[]{Integer.TYPE});
                    SCardEstablishContext.setAccessible(true);



                    Field SCARD_SCOPE_USER =
                            pcsc.getDeclaredField("SCARD_SCOPE_USER");
                    SCARD_SCOPE_USER.setAccessible(true);

                    long newId = ((Long) SCardEstablishContext.invoke(pcsc, new Object[]{Integer.valueOf(SCARD_SCOPE_USER.getInt(pcsc))})).longValue();
                    contextId.setLong(pcscterminal, newId);
                }
            } catch (Exception ex) {
            }
    ///////////////////////////////////////////////////////////////////////////////////////////////////////////////

            TerminalFactory factory = null;
            List<CardTerminal> terminals = null;
            try {
                factory = TerminalFactory.getDefault();

                terminals = factory.terminals().list();
            } catch (Exception ex) { //
                Logger.getLogger(NFC_Test.class.getName()).log(Level.SEVERE,null, ex);
            }

            if (factory != null && factory.terminals() != null && terminals
                    != null && terminals.size() > 0) {
                try {
                    CardTerminal terminal = terminals.get(0);

                    if (terminal != null) {

                        System.out.println(terminal);
                        if (terminal.isCardPresent()) {
                            System.out.println("Card");
                        } else {
                            System.out.println("No Card");
                        }

                    } else {
                        System.out.println("No terminal");
                    }

                    terminal = null;
                } catch (Exception e) {
                    Logger.getLogger(NFC_Test.class.getName()).log(Level.SEVERE,null, e);
                }
                factory = null;

                terminals = null;

                Runtime.getRuntime().gc();

            } else {
                System.out.println("No terminal");
            }

        }
    }
}

上面的代码在Windows操作系统中工作正常,但是当我在MAC OS上运行时,应用程序运行完美5-10秒,然后突然崩溃,出现以下内存错误。

Above code is working fine in Windows OS but when I run it on MAC OS then application runs for 5-10 seconds perfectly but then it suddenly crash with the following memory error.

java(921,0x10b0c3000) malloc: *** mmap(size=140350941302784) failed (error code=12)
*** error: can't allocate region
*** set a breakpoint in malloc_error_break to debug
Java Result: 139

我在互联网上搜索,找不到任何有关上述内存错误的信息。我还包括了内存管理代码,当它在计时器中使用时,通过为它分配NULL值来释放对象。

I searched on internet and cannot find anything regarding above memory error. Also I included the code for memory management to release the object when it is used in timer by assigning NULL value to it.

我使用了 http://ludovicrousseau.blogspot.com/2010/06/pcsc-sample-in-java。 html 供参考

推荐答案

我认为这是我在尝试追踪错误时遇到的错误之一在OS X上的64位Java上使用libj2pcsc.dylib。另请参阅discussion.apple.com上的 smartcardio thread 和我的发送电子邮件给security-dev 。基本上,问题是 DWORD * 应该是OS X上32位数字的指针,但是Sun的库假设它是指向64位数字的指针。然后它取消引用该值并尝试malloc一个大小的缓冲区,该缓冲区可以包含高32位的垃圾。请参阅 Java_sun_security_smartcardio_PCSC_SCardListReaders sun / security / smartcardio / pcsc.crel =nofollow> pcsc.c的来源

I believe this was one of the errors I was getting when trying to track down the bugs with libj2pcsc.dylib on 64-bit Java on OS X. See also smartcardio thread on discussions.apple.com and my email to security-dev. Basically, the problem is that DWORD* should be a pointer to a 32-bit number on OS X, but Sun’s library assumed that it was a pointer to a 64-bit number. Then it dereferences that value and tries to malloc a buffer of that size, which can contain junk in the upper 32 bits. See Java_sun_security_smartcardio_PCSC_SCardListReaders in the source of pcsc.c

潜在的解决方法:


  • 通过调用 Terminals.list()(间歇性崩溃)非常保守,并且不信任结果 Terminal.isCardPresent() Terminals.waitForChange(long),或 CardTerminal .waitForCard(boolean,long)。我的同事意识到他可以使用反射调用 TerminalImpl.SCardGetStatusChange(long,long,int [],String [])来获得正确的结果。这就是我们以前做的事情。非常痛苦!

  • 修复libj2pcsc.dylib的头文件并重新编译OpenJDK。这就是我们现在在公司所做的事情。

  • 切换到 javax.smartcardio 的不同实现。我知道两个:我自己的 jnasmartcardio intarsys / smartcard-io 。但是,我没有在NFC卡上尝试过自己的库,但我欢迎任何错误报告和补丁。

  • Be very conservative with calls to Terminals.list() (which crashes intermittently), and don’t trust the results of Terminal.isCardPresent(), Terminals.waitForChange(long), or CardTerminal.waitForCard(boolean, long). My co-worker realized that he could call TerminalImpl.SCardGetStatusChange(long, long, int[], String[]) using reflection to get the right results. This is what we used to do. Very painful!
  • Fix the header files for libj2pcsc.dylib and recompile OpenJDK. This is what we do at my company right now.
  • Switch to a different implementation of javax.smartcardio. I know of two: my own jnasmartcardio and intarsys/smartcard-io. I have not tried my own library on NFC cards, however, but I welcome any bug reports and patches.

这篇关于使用JAVA智能卡API读取NFC标签不适用于MAC OS的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆