Android HCE应用安全消息问题:AID选择返回SW 6E00(无效类)
Android HCE安全消息下AID选择的问题解答
核心结论
Android HCE支持安全消息(Secure Messaging)下的AID选择,但需要适配系统对SELECT命令的特殊处理逻辑。
问题原因分析
你遇到的SW 6E00(无效类)错误,核心原因是:Android HCE框架会优先拦截并处理CLA=00的SELECT AID命令,用于完成静态/动态AID的路由匹配;但对于CLA非00(比如你使用的0C,对应安全消息加密的命令类)的SELECT命令,框架不会自动进行路由处理,而是直接返回6E00,除非你在主Applet中手动接管这类SELECT命令的处理逻辑。
而测试中READ BINARY能正常进入processCommandApdu,是因为框架不会拦截这类非SELECT的APDU,会直接转发给当前选中的Applet处理。
正确实现方式
1. 在主Applet中手动处理安全消息加密的SELECT命令
当PACE安全通道建立后,所有加密的APDU(包括SELECT)都会以CLA=0C的形式发送,此时需要在主Applet的processCommandApdu方法中执行以下步骤:
- 先解密安全消息,解析出原始的SELECT命令(CLA=00,INS=A4格式)
- 验证目标AID是否已经通过
registerAidsForService完成动态注册 - 如果AID已注册,返回加密后的成功响应,触发系统路由到目标Applet;如果未注册,返回对应错误码(比如
6A82)
2. 动态注册第二个Applet的注意事项
- 动态注册AID时,必须使用
HostApduService的registerAidsForService方法,传入正确的AID列表和对应服务组件信息 - 注册完成后,系统会将后续匹配该AID的非加密SELECT命令自动路由到对应Applet,但加密的SELECT仍需主Applet先解密处理
关键代码示例
@Override public byte[] processCommandApdu(byte[] apdu, Bundle extras) { // 判断是否为安全消息加密命令(CLA=0C) if ((apdu[0] & 0xFF) == 0x0C) { // 解密安全消息,得到原始APDU byte[] decryptedApdu = decryptSecureMessaging(apdu); // 判断是否为SELECT命令(INS=A4) if ((decryptedApdu[1] & 0xFF) == 0xA4) { // 提取目标AID byte[] targetAid = extractAidFromSelectApdu(decryptedApdu); // 检查AID是否已动态注册 if (isAidRegistered(targetAid)) { // 返回加密后的成功响应 byte[] successSw = new byte[]{(byte)0x90, (byte)0x00}; return encryptSecureMessaging(successSw); } else { // 返回AID未找到的加密响应 byte[] notFoundSw = new byte[]{(byte)0x6A, (byte)0x82}; return encryptSecureMessaging(notFoundSw); } } } // 处理其他命令或转发到对应逻辑 return super.processCommandApdu(apdu, extras); }
补充说明
- Android HCE框架的SELECT命令入口管理逻辑属于系统内部实现,并未对外暴露,因此无法在公开API文档中找到相关内容
- 动态注册的AID必须和静态注册的AID属于同一个应用的
HostApduService组件,否则无法正常完成路由
内容的提问来源于stack exchange,提问作者Monssif
相关产品推荐
相关产品推荐

