ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

android – 有没有办法检查终端是否收到了主机卡仿真中的最后一条消息?

2019-07-01 15:12:01  阅读:267  来源: 互联网

标签:android nfc apdu contactless-smartcard hce


在我的Android应用程序中,我有HostApduService的实现.以下是它的实现片段:

public final class MyHostApduService extends HostApduService {

    private boolean disconnected = false;

    @Override
    public byte[] processCommandApdu(byte[] commandApdu, @Nullable Bundle extras) {
        //process apdu in a background thread and call sendResponseApdu() when ready
        Single.fromCallable(() -> processInternal(commandApdu))
                .subscribeOn(nfcScheduler)
                .subscribe(this::sendResponseApdu, t -> Log.e("could not create response", t));
        return null;
    }

    ...
    @Override
    public void onDeactivated(int reason) {
       disconnected = true;
    }


    private void processInternal(byte[] apdu) {
        //business logic
        if(!disconnected) {
           //last message was probably received by the terminal
        }
    }
}

因此,在我的观察中,onDeactivated()回调可以在processCommandApdu()的中间进行,甚至那时OS似乎更早地认识到NFC字段丢失比调用onDeactivated()更早.

以下是通信过程中丢失字段的示例:

16:21:16.808 I/MyHostApduService : processApdu[request|13bytes] 0A4040007A0000000043
public final class MyHostApduService extends HostApduService {

    private boolean disconnected = false;

    @Override
    public byte[] processCommandApdu(byte[] commandApdu, @Nullable Bundle extras) {
        //process apdu in a background thread and call sendResponseApdu() when ready
        Single.fromCallable(() -> processInternal(commandApdu))
                .subscribeOn(nfcScheduler)
                .subscribe(this::sendResponseApdu, t -> Log.e("could not create response", t));
        return null;
    }

    ...
    @Override
    public void onDeactivated(int reason) {
       disconnected = true;
    }


    private void processInternal(byte[] apdu) {
        //business logic
        if(!disconnected) {
           //last message was probably received by the terminal
        }
    }
}

16:21:16.811 D/MyHostApduService : do business logic
16:21:16.890 D/HostEmulationManager: notifyHostEmulationDeactivated
16:21:16.890 D/HostEmulationManager: Unbinding from service ComponentInfo{app.debug/internal.MyHostApduService}
16:21:16.890 I/MyHostApduService : onDeactivated LINK_LOSS
16:21:16.898 I/MyHostApduService : processApdu[response|2bytes|90ms] 6A82

解决方法:

你不能.相反,如果您确实需要可靠地检测到该情况,则需要调整通信协议.

问题不是Android,而是基础通信协议(ISO / IEC 7844-4,ISO / IEC 14443-4).这些协议是为与常规智能卡通信而构建的.智能卡是完全无源的设备,当从读卡器中拉出或远离NFC RF场时,不能继续处理(由于缺乏能量).

协议栈设计用于询问器驱动的通信(其中询问器是终端).通信在命令 – 响应序列中执行.原则上,每个命令响应序列包括以下步骤(带有一些额外的极端情况):

>终端发送命令.
>智能卡接收并处理命令.
>智能卡发送响应数据并以状态字结束.

应用协议(ISO / IEC 7816-4)和传输协议(ISO / IEC 14443-4又名ISO-DEP)都不通过任何形式的确认来确认智能卡响应.一旦智能卡发送其响应,就认为已完成处理.

实际上,这对于经典智能卡(接触式或非接触式)来说不是问题.中断的通信将导致卡重新上电(因为链路丢失也意味着功率损耗或者因为终端执行显式重置).因此智能卡将无法在此时依赖清理序列.

但是,这并不意味着没有办法克服这种限制.经典智能卡即使在电源循环中也能保持持久状态.关键操作作为原子事务执行.在断电的情况下,通常在复位(启动)时执行清理/回滚.但是,由于链接丢失不会导致HCE端的执行被中断,因此映射到Android并不容易.因此,在将响应发送回读取器之前,无法检测到HCE智能卡被拉出.然而,也没有可能被链路丢失中断的原子事务.因此,重置(即接收选择应用程序的SELECT(通过DF名称)命令)仍然是执行清理的正确位置,例如重置应用程序状态.

关于您的特定要求,典型的方法是调整应用程序级协议并添加确认命令,以确认接收(然后是第二个)最后一个响应.即如果你现在有类似的东西:

T--->  SELECT APPLICATION
<---C  FCI | 9000
T--->  PERFORM CRITICAL OPERATION
<---C  CRITICAL OPERATION RESULT

您可以调整协议以包含最终确认:

T--->  SELECT APPLICATION
<---C  FCI | 9000
T--->  PERFORM CRITICAL OPERATION
<---C  CRITICAL OPERATION RESULT
T--->  CONFIRM RECEPTION OF RESULT
<---C  9000

现在你真的不在乎最终的响应(9000)是否在去往终端的路上丢失了.

标签:android,nfc,apdu,contactless-smartcard,hce
来源: https://codeday.me/bug/20190701/1348009.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有