Android Safety 系列专题【篇六:SecureElement安全硬件】

针对本系列前面几篇有提到安全硬件,但是这块接触的比较少,唯一接触到的场景有SecureElement,本篇主要就是围绕SecureElement的使用和相关案例进行解说。

一、SecureElement框架

Secure Element(安全元件)本质上是一个"高安全级别的执行与存储环境",专门用来存放敏感数据(比如密钥、证书、银行卡数据)并在受硬件保护的环境里执行安全逻辑(比如加解密、支付、认证),对外通过严格受控的接口提供服务。

Secure Element(简称SE)是一种以芯片形式存在的专用硬件组件。它通过物理隔离与防篡改设计来保护敏感数据,免受未经授权的访问,内部集成了加密/解密逻辑电路,并且与主处理器隔离运行,确保数据的安全性。

主要功能如下:

  • 物理隔离与安全保护‌:SecureElement具有独立的执行环境和安全存储,软件和硬件上都具备防篡改能力。其内部组件包含CPU、RAM、ROM、加密引擎等。
  • 安全存储与加密运算‌:它能够安全地存储密钥、证书、个人隐私数据等敏感信息,并提供数据加密运算功能。主要功能包括密钥的安全存储、数据加密运算和信息的安全存放。
  • 多种实现形式‌:SecureElement可以封装成不同的形式,包括智能卡、嵌入式安全模块(eSE)、UICC(通用集成电路卡)以及Micro SD卡等。其中,eSE是嵌入在手机内部的芯片,UICC是SIM卡,Micro SD则是通过SD卡槽集成的芯片。

Secure Element 主要用于需要高安全级别的应用场景,常见形态如下:

  • **eSE:**全称embedded Secure Element(嵌入式安全单元),一般是焊在主板上的一块安全芯片,不是"SIM 卡槽"那种可插拔形式。在手机里,这块eSE很常见的用途是和NFC绑在一起做安全支付(比如公交卡、门禁、银行卡等),因为NFC控制器可以通过硬件连线(SWP/I2C/SPI 等)访问这块 eSE
  • UICC:SIM 卡上的 SE,运营商的 SIM/USIM/eSIM 卡本身就带有 SE 功能,Android SIM1/SIM2 就是把 SIM 卡当作一个 SE。
  • SD:带 SE功能的SD卡,这种比较少。

Secure Element 作为安全存储芯片,和普通存储/CPU 的区别:

  • 有独立的安全认证与访问控制逻辑(像你看到的 AccessControlEnforcer、AID 权限规则)。
  • 针对物理攻击、防篡改、防侧信道攻击做过专门设计与认证(例如符合某些安全等级标准)。
  • 即便系统被 Root / 内核被攻破,要从 SE 里直接把密钥"拽"出来也非常困难。

Secure Element 和前文介绍的TEE这些又有什么样的关系呢?

  • TEE(TrustZone 内的安全世界)也是一种安全执行环境,但通常和 AP 同一颗 SoC,不一定是"独立芯片",抽象层次略不同。
  • TPM(传统 PC 上的可信模块)在"安全存储+安全操作"这个职责上和 SE 很像,只是接口与生态不同。
  • 你可以粗略地把 SE 理解为"手机里的类似 TPM 的安全元件",只是形态可以是 eSE 芯片、SIM 卡等。

一句话总结Secure Element 就是手机里专门负责"高安全等级存储和执行(如支付、认证、加密)"的安全硬件/安全环境,在 Android 中通过 OMAPI 以 Reader / Session / Channel 的形式对外提供受控访问。

1、SecureElement应用端

在AOSP原生系统中,是存在一个叫做SecureElement的应用,应用源码路径在packages/apps/SecureElement:

在AOSP原生目录build/make/target/product/handheld_system.mk中进行预装,注意低配置的设备不支持此应用:

那么这个应用的关键信息有哪些呢?根据如下代码可以了解到:

  • 包名:com.android.se
  • 核心服务:SecureElementService
  • 引用hardware库

1)SecureElementService服务注册

此应用没有界面,但是有一个核心服务SecureElementService,在应用创建的时候启动:

java 复制代码
//packages/apps/SecureElement/src/com/android/se/SEApplication.java
//Starts the SecureElementService.
public class SEApplication extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        Intent serviceIntent = new Intent(getApplicationContext(), SecureElementService.class);
        startService(serviceIntent);
    }
}

SecureElementService作为APP层的核心服务,实现服务的生命周期:

java 复制代码
//packages/apps/SecureElement/src/com/android/se/SecureElementService.java
public final class SecureElementService extends Service {
    private final String mTag = "SecureElementService";
    //此服务支持两个终端:SIM和eSE
    public static final String UICC_TERMINAL = "SIM";
    public static final String ESE_TERMINAL = "eSE";
    public static final String VSTABLE_SECURE_ELEMENT_SERVICE = "android.se.omapi.ISecureElementService/default";
    @Override
    public IBinder onBind(Intent intent) {
        Log.i(mTag, Thread.currentThread().getName() + " onBind");
        if (ISecureElementService.class.getName().equals(intent.getAction())) {
            return mSecureElementServiceBinder;
        }
        return null;
    }
    @Override
    public void onCreate() {
        super.onCreate();
        Log.i(mTag, Thread.currentThread().getName() + " onCreate");
        initialize();
        //创建两个终端:SIM和eSE
        createTerminals();
        // Add vendor stable service only if it is configured
        //向servicemanager注册android.se.omapi.ISecureElementService/default服务
        if (getResources().getBoolean(R.bool.secure_element_vintf_enabled)) {
            ServiceManager.addService(VSTABLE_SECURE_ELEMENT_SERVICE, mSecureElementServiceBinderVntf);
        }
        // Since ISecureElementService is marked with VINTF stability
        // to use this same interface within the system partition, will use
        // forceDowngradeToSystemStability and register it.
        mSecureElementServiceBinder.forceDowngradeToSystemStability();
        //向servicemanager注册secure_element服务
        ServiceManager.addService(Context.SECURE_ELEMENT_SERVICE, mSecureElementServiceBinder);
    }
    //secure_element服务的具体实现
    private final ISecureElementService.Stub mSecureElementServiceBinder = new SecureElementServiceBinder();
    //android.se.omapi.ISecureElementService/default服务的具体实现
    private final ISecureElementService.Stub mSecureElementServiceBinderVntf =  new SecureElementServiceBinder();
}

如上向系统注册了secure_element服务,但是服务的具体实现如下:

如上代码如下:

  • com.android.se应用维护了名叫做SecureElementService的服务
  • com.android.se应用把SecureElementService注册成为了系统级服务
  • com.android.se应用作为服务端应用进程,提供了如下功能:
  • getReaders():拿到所有 SE 读卡器名字。
  • getReader(name):拿到指定 Reader(背后是 Terminal.SecureElementReader)。
  • isNfcEventAllowed():检查 NFC 事件是否允许发给某些 App。

因此可以看出SecureElementService服务管理了系统所有的安全芯片,并对外提供了OMAPI接口,主要暴露了如上三个接口。

2)SIM & eSE 终端管理

SecureElementService服务是如何管理系统所有支持的安全芯片呢?

仔细阅读此服务的代码,可以了解到一个叫做Terminal的概念,具体实现是在Terminal.java里面。

这里先说一下我的理解:Terminal翻译过来就是终端,可以看到一个SE芯片对应一个终端,例如SIM安全卡槽和eSE安全卡槽。

SecureElementService服务启动初始化的时候,注册了卡槽插拔事件,用于创建管理维护安全芯片列表mTerminals,如下经典代码:

java 复制代码
//packages/apps/SecureElement/src/com/android/se/SecureElementService.java
public final class SecureElementService extends Service {
    //主要两大类终端:SIM和eSE
    public static final String UICC_TERMINAL = "SIM";
    public static final String ESE_TERMINAL = "eSE";
    // LinkedHashMap will maintain the order of insertion
    private LinkedHashMap<String, Terminal> mTerminals = new LinkedHashMap<String, Terminal>();
    private int mActiveSimCount = 0;
    //核心流程一:添加UICC_TERMINAL终端
    private void initialize() {
        // 注册监听当前系统SIM卡槽获取数量
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(TelephonyManager.ACTION_MULTI_SIM_CONFIG_CHANGED);
        this.registerReceiver(mMultiSimConfigChangedReceiver, intentFilter);
    }
    private final BroadcastReceiver mMultiSimConfigChangedReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            if (action.equals(TelephonyManager.ACTION_MULTI_SIM_CONFIG_CHANGED)) {
                int activeSimCount = intent.getIntExtra(TelephonyManager.EXTRA_ACTIVE_SIM_SUPPORTED_COUNT, 1);
                Log.i(mTag, "received action MultiSimConfigChanged. Refresh UICC terminals");
                Log.i(mTag, "Current ActiveSimCount:" + activeSimCount + ". Previous ActiveSimCount:" + mActiveSimCount);
                // 刷新SIM终端数量
                refreshUiccTerminals(activeSimCount);
            }
        }
    };
    // 最后通过addTerminals去添加UICC_TERMINAL终端
    private void refreshUiccTerminals(int activeSimCount) {
        String name = null;
        synchronized (this) {
            if (activeSimCount < mActiveSimCount) {
                // Remove non-supported UICC terminals
                for (int i = activeSimCount + 1; i <= mActiveSimCount; i++) {
                    name = UICC_TERMINAL + Integer.toString(i);
                    Terminal terminal = mTerminals.get(name);
                    if (terminal != null) {
                        terminal.closeChannels();
                        terminal.close();
                    }
                    mTerminals.remove(name);
                    Log.i(mTag, name + " is removed from available Terminals");
                }
                mActiveSimCount = activeSimCount;
            } else if (activeSimCount > mActiveSimCount) {
                // Try to initialize new UICC terminals
                addTerminals(UICC_TERMINAL);
            }
        }
    }
    //核心流程二:添加ESE_TERMINAL终端
    @Override
    public void onCreate() {
        super.onCreate();
        Log.i(mTag, Thread.currentThread().getName() + " onCreate");
        initialize();
        createTerminals();
        //.......服务注册
    }
    //不需要判断,直接添加ESE_TERMINAL,因为是内置的
    private void createTerminals() {
        // Check for all SE HAL implementations
        addTerminals(ESE_TERMINAL);
        if (!SystemProperties.getBoolean("ro.radio.noril", false)) {
            addTerminals(UICC_TERMINAL);
       }
    }
    //核心流程三:addTerminals添加总段,其实
    private void addTerminals(String terminalName) {
        int index = 1;
        int uicc_count = 0;
        String name = null;
        TelephonyManager mTelephonyManager;
        mTelephonyManager = (TelephonyManager)  getSystemService(Context.TELEPHONY_SERVICE);
        uicc_count = mTelephonyManager.getPhoneCount();
        if (terminalName.startsWith(SecureElementService.UICC_TERMINAL))  index = mActiveSimCount + 1;
        try {
            do {
                if((terminalName.equals(UICC_TERMINAL)) && (index > uicc_count)) break;
                name = terminalName + Integer.toString(index);
                //核心代码:实例化对象Terminal
                Terminal terminal = new Terminal(name, this);
                Log.i(mTag, "Check if terminal " + name + " is available.");
                // Only retry on fail for the first terminal of each type.
                terminal.initialize(index == 1);
                //核心代码:添加到SE列表mTerminals中
                mTerminals.put(name, terminal);
                if (terminalName.equals(UICC_TERMINAL)) mActiveSimCount = index;
            } while (++index > 0);
        } catch (NoSuchElementException e) {
            Log.i(mTag, "No HAL implementation for " + name);
        } catch (RemoteException | RuntimeException e) {
            Log.e(mTag, "Error in getService() for " + name);
        }
    }
}

总结如上代码:

  • 先监听ACTION_MULTI_SIM_CONFIG_CHANGED广播,进行添加或者移除SIM
  • 然后直接添加eSE
  • 最后判断系统如果支持蜂窝功能添加SIM
  • 添加SE终端设备的方式就是直接new Terminal(),然后添加到mTerminals列表中

3)Terminal如何与HAL层通信?

Terminal 表示"一块具体的 Secure Element(比如某个 eSE1 或 SIM1)",负责这块 SE 的生命周期管理、和 HAL 的通信、通道(Channel)管理,以及访问控制(ACL)。

A Terminal连接hardware层

内部逻辑:

  • 先尝试 android.hardware.secure_element.ISecureElement(AIDL)。
  • 再尝试 android.hardware.secure_element.V1_2.ISecureElement。
  • 再尝试 V1_1 / V1_0。
  • 成功后调用 init(...) 注册回调,并 linkToDeath(...) 监听进程死亡。
  • 实际业务调用 HAL:
  • mAidlHal.getAtr() / mSEHal.getAtr() → 获取 ATR。
  • mAidlHal.openBasicChannel() / mSEHal.openBasicChannel() → 开 basic channel。
  • mAidlHal.openLogicalChannel() / mSEHal.openLogicalChannel() → 开 logical channel。
  • mAidlHal.transmit() / mSEHal.transmit() → 发送 APDU。
  • mAidlHal.closeChannel() / mSEHal.closeChannel() → 关闭通道。
  • mAidlHal.isCardPresent() / mSEHal.isCardPresent() → 判断卡是否在。
  • mAidlHal.reset() / mSEHal12.reset() → 触发 SE reset。

可以把 Terminal 看成 "framework(OMAPI) ↔ HAL 之间的适配器"。

B Terminal暴露接口

与 HAL/状态相关

  • initialize(boolean retryOnFail):初始化与 HAL 的连接。
  • getAtr():拿当前 SE 的 ATR。
  • isSecureElementPresent():是否有卡/SE 在。
  • reset():reset Secure Element。
  • stateChange(boolean state, String reason)(内部):处理 HAL 状态回调,更新连接状态、重建 ACL。

通道管理

  • openBasicChannel(SecureElementSession session, byte\[\] aid, byte p2, ISecureElementListener listener, String packageName, byte\[\] uuid, int pid)
  • openLogicalChannel(SecureElementSession session, byte\[\] aid, byte p2, ISecureElementListener listener, String packageName, byte\[\] uuid, int pid)
  • openLogicalChannelWithoutChannelAccess(byte\[\] aid):内部使用,不做 ACL。
  • closeChannel(Channel channel)
  • closeChannels()
  • close():解绑 death recipient

APDU 相关

  • transmit(byte\[\] cmd):带 6C/61 处理的高层 transmit。
  • transmitInternal(byte\[\] cmd):直接调 HAL 的低层 transmit。
  • selectDefaultApplication() / 私有 select(byte\[\] aid):在 basic channel 上 select 应用。

访问控制 & NFC 事件

  • isNfcEventAllowed(PackageManager pm, byte\[\] aid, String\[\] packageNames):NFC 事件是否允许给某些 App
  • checkCarrierPrivilegeRules(PackageInfo pInfo):检查 carrier privilege
  • getAccessControlEnforcer()、setUpChannelAccess(...)、initializeAccessControl():ACL 初始化和通道访问权限设置
  • isAidSelectable(byte\[\] aid):检测某 AID 是否可以被 select(内部通过打开/关闭逻辑通道试探)。

最后一句话理解Terminal :一块具体 Secure Element(比如某张 SIM 卡或某个 eSE 芯片)的"驱动+管家":它一边直接和 HAL 打交道(开关通道、收发 APDU、reset),一边负责管理这块 SE 上所有的 channel/session,并通过访问控制组件决定哪些 App/UUID 能访问哪些 AID 和 NFC 事件。

2、secure_element硬件抽象层

SecureElement.apk虽然是一个apk的形态出现在我们的眼前,包名为com.android.se,但是在SecureElementService中给系统注册了secure_element服务,维护管理了UICC和eSM安全芯片设备,并以Terminal作为桥梁直接调用到了硬件抽象层,本节就针对secure_element硬件抽象层进行初步认识。

如上AOSP原生代码路径/hardware/st/目录下实现了nfc和secure_element两个模块的硬件抽象层。

同上面的介绍,nfc与secure_element其实是两个独立的模块:

  • nfc:负责射频收发,是"天线 + 射频前端 + 协议栈",对外表现为"刷卡"的接口。
  • secure_element:是一个高安全等级的"安全芯片/安全执行环境",用来存储密钥、证书、支付应用、交通卡应用等敏感数据,并在里面执行加解密、认证逻辑。

那么他们之间到底有什么联系呢?在很多设计里,NFC 控制器和 SE 之间有一条专用接口(如 SWP、DCLB、I²C/SPI 等),NFC 负责与读卡器或手机外部设备通信,再把 APDU 等命令透传给 SE,由 SE 完成安全处理。这是否可以理解se和tee之间到底有什么区别了吗?

本节跳过nfc,重点来看看secure_element,很明显在A16上面secure_element实现了两份,我们直接来看secure_element2吧:

bash 复制代码
.
├── Android.bp
├── LICENSE
├── METADATA
├── MODULE_LICENSE_APACHE2
├── NOTICE -> LICENSE
├── OWNERS
└── secure_element
    ├── 1.0
    │   ├── Android.bp
    │   ├── android.hardware.secure_element@1.0-service-gto-ese2.rc
    │   ├── android.hardware.secure_element@1.0-service-gto.rc
    │   ├── GtoService.cpp
    │   ├── GtoService_ese2.cpp
    │   ├── SecureElement.cpp
    │   ├── SecureElement.h
    │   ├── SecureElementHalCallback.cpp
    │   ├── SecureElementHalCallback.h
    │   └── se-gto
    │       └── libse-gto.h
    ├── 1.1
    │   ├── Android.bp
    │   ├── android.hardware.secure_element@1.1-service-gto-ese2.rc
    │   ├── android.hardware.secure_element@1.1-service-gto.rc
    │   ├── GtoService.cpp
    │   ├── GtoService_ese2.cpp
    │   ├── SecureElement.cpp
    │   ├── SecureElement.h
    │   └── se-gto
    │       └── libse-gto.h
    ├── 1.2
    │   ├── Android.bp
    │   ├── android.hardware.secure_element@1.2-service-gto-ese2.rc
    │   ├── android.hardware.secure_element@1.2-service-gto.rc
    │   ├── GtoService.cpp
    │   ├── GtoService_ese2.cpp
    │   ├── SecureElement.cpp
    │   ├── SecureElement.h
    │   └── se-gto
    │       └── libse-gto.h
    ├── aidl
    │   ├── Android.bp
    │   ├── android.hardware.secure_element_gto-ese2.rc
    │   ├── android.hardware.secure_element_gto-ese2.xml
    │   ├── android.hardware.secure_element_gto.rc
    │   ├── android.hardware.secure_element_gto-st33.rc
    │   ├── android.hardware.secure_element_gto-st33.xml
    │   ├── android.hardware.secure_element_gto.xml
    │   ├── GtoService.cpp
    │   ├── GtoService-ese2.cpp
    │   ├── GtoService-st33.cpp
    │   ├── SecureElement.cpp
    │   ├── SecureElement.h
    │   └── se-gto
    │       └── libse-gto.h
    ├── esehal
    │   ├── Android.bp
    │   └── src
    │       ├── checksum.c
    │       ├── checksum.h
    │       ├── compiler.h
    │       ├── iso7816_t1.c
    │       ├── iso7816_t1.h
    │       ├── libse-gto.c
    │       ├── libse-gto-private.h
    │       ├── linux
    │       │   └── se_gemalto.h
    │       ├── log.c
    │       ├── log.h
    │       ├── se-gto
    │       │   └── libse-gto.h
    │       ├── spi.c
    │       ├── spi.h
    │       ├── transport.c
    │       └── transport.h
    ├── libse-gto-hal.conf
    └── libse-gto-hal-ese2.conf

关于secure_element hardware没有什么好讲的,但是在XTS中会经常遇到,后文通过XTS来进行介绍吧。

二、MTK OMAPIXTS 分析指南

MTK有官方网站介绍:https://online.mediatek.com/apps/faq/detail?faqid=FAQ39642&list=SW。本节内容完全拷贝MTK的总结

摘要:本文档针对 OMAPI(Open Mobile API)相关的 xTS 测试失败问题提供排查思路和解决方案,涵盖 CtsOmapiTestCases、CtsSecureElementAccessControlTestCases 和 VtsHalSecureElement。问题通常由 OMAPI 配置、SecureElement HAL Service 状态异常或测试环境(测试白卡/eSIM Profile)不合规引起。

PS:本章完全摘抄MTK官方网站

1、常见问题

  • 在 CTS 认证时遇到 CtsOmapiTestCases 失败,报错 OpenLogicalChannel() failedAccessControlException,如何解决?
  • 如果项目不需要支持 NFC/OMAPI 功能,如何通过配置跳过 OMAPI 相关的 xTS 测试?
  • 1 eSIM + 1 实体 SIM 架构下,eSIM 不需要支持 OMAPI,如何配置以满足 xTS 测试要求?

2、问题原因

OMAPI 相关 xTS 测试失败通常由以下原因引起:

原因1:测试使用的 SIM 卡不合规

该测试要求插入符合 Google CTS 要求的测试白卡。对于 eSIM 项目,需要 eSIM 提供方提供符合 Google CTS 要求的专用 Profile。否则 SecureElement 的访问控制(AccessControlEnforcer)无法在 SIM 卡或 eSIM 中找到对应的访问规则,导致测试失败。

Google 官网的相关说明:https://source.android.com/compatibility/cts/secure-element

典型日志示例1(Access Control 规则缺失):

复制代码
SecureElement-PKCS15Handler: - Loading SIM2 rules...
TestRunner: java.lang.AssertionError: Unexpected Exception java.lang.SecurityException: Exception in setUpChannelAccess()
java.security.AccessControlException: SecureElement-AccessControlEnforcerno APDU access allowed!

典型日志示例2(OpenLogicalChannel 失败):

复制代码
java.lang.AssertionError: Unexpected Exception java.io.IOException: OpenLogicalChannel() failed

典型日志示例3(APDU 传输失败):

复制代码
MtkUiccSEHal: [se2]transmitInternalLocked:657: [121] > transmit [2] 02C27FFF00
MtkUiccSEHal: [se2]transmitInternalLocked:705: [121] < transmit [2] 0000 err=2

原因2:SecureElement APK 不存在

典型日志:

复制代码
I/ModuleListener: [1/1] android.omapi.cts.OmapiTest#testOpenBasicChannelNullAid fail:
java.lang.AssertionError: Unexpected Exception java.util.concurrent.TimeoutException: Service could not be connected after 3000 ms

原因3:Feature声明,HAL 声明与 HAL Service 运行状态不匹配

系统声明了 android.hardware.se.omapi.uicc feature,device manifest 中声明了 ISecureElement,但 HAL Service (/vendor/bin/hw/android.hardware.secure_element@1.2-service-mediatek) 未运行。

典型日志:

复制代码
ServiceManagerCppClient: Waited one second for android.hardware.secure_element.ISecureElement/SIM1 (is service started? Number of threads started in the threadpool: 16. Are binder threads started and available?)

3、排查方法

步骤0:确认 SIM 卡是否合规

如果看到上节所述 Access Control 规则缺失、OpenLogicalChannel 失败、APDU 传输失败的典型日志,检查是否使用的是 CTS 测试白卡或 CTS 专用 eSIM Profile。

注意:不同 eSIM 厂商的测试 profile 可能不通用,务必从对应的 eSIM 厂商获取 profile

步骤1:检查 SecureElement APK

复制代码
adb shell ls /system/app/SecureElement

SecureElement APK 是 AOSP 原生就存在的 APK,如果不存在,检查是否客制化移除。

步骤2:检查 Feature 声明

复制代码
adb shell cat /vendor/etc/permissions/android.hardware.se.omapi.prebuilt.xml

如果声明了 android.hardware.se.omapi.uicc, 结果为:

复制代码
...
<permissions>
    <feature name="android.hardware.se.omapi.uicc" />
</permissions>

步骤3:检查 manifest

复制代码
adb shell "grep -A4 ISecureElement /vendor/etc/vintf/manifest.xml"

如果声明了 ISecureElement HAL,结果为(Android U 及之后):

复制代码
        <fqname>ISecureElement/SIM1</fqname>
        <fqname>ISecureElement/SIM2</fqname>
		     ...

或者 (Android T 及之前)

复制代码
        <name>ISecureElement</name>
        <interface>SIM1</interface>
        <interface>SIM2</interface>
		     ...

步骤4:检查 HAL service

复制代码
adb shell "ps -A | grep secure_element"

如下结果显示 HAL service 正常运行:

复制代码
secure_element 1335    1   10940052   7492 binder_thread_read  0 S android.hardware.secure_element@1.2-service-mediatek

步骤5:检查配置一致性

MTK 在 /device/mediatek/vendor/common/device.mk 中通过 MTK_OMAPI_SUPPORT 宏保证了 feature、manifest、HAL service 的同开同关。
如果上述 feature/manifest/HAL service 存在状态不一致

  • 检查 device.mk 是否有客制化
  • 检查是否在其他地方修改了 feature/manifest/HAL service 配置

/device/mediatek/vendor/common/device.mk

复制代码
ifeq ($(strip $(MTK_OMAPI_SUPPORT)), yes)
  ifeq ($(strip $(MTK_MULTI_SIM_SUPPORT)), ss)
    DEVICE_MANIFEST_FILE += $(LOCAL_PATH)/project_manifest/manifest_secure_element_ss$(ESE_MANIFEST).xml
  endif
  ifeq ($(strip $(MTK_MULTI_SIM_SUPPORT)), dsds)
    DEVICE_MANIFEST_FILE += $(LOCAL_PATH)/project_manifest/manifest_secure_element_dsds$(ESE_MANIFEST).xml
  endif
  ...
  ...
  PRODUCT_PACKAGES += android.hardware.se.omapi.prebuilt.xml
  PRODUCT_PACKAGES += mailto:android.hardware.secure_element@1.2-service-mediatek
  ...
  ...
endif

4、解决方案

方案一:彻底关闭OMAPI支持

📌 适用场景:设备不需要UICC OMAPI能力(不支持NFC/OMAPI的项目)

操作步骤

  1. 关闭宏配置

    复制代码
    MTK_OMAPI_SUPPORT = no
  2. 确认Feature声明

    确认 /vendor/etc/permissions/ 下没有 android.hardware.se.omapi.prebuilt.xml

  3. 确认device Manifest

    确认 /vendor/etc/vintf/manifest.xml 中没有声明 ISecureElement

  4. 确认服务状态

    复制代码
    adb shell "ps -A | grep secure_element"

    确认没有相关服务在运行


方案二:单独对特定卡槽(如SIM2/eSIM)禁用OMAPI

📌 适用场景:1 eSIM + 1 实体SIM架构,且eSIM不需要支持OMAPI

操作步骤

  1. 修改Manifest文件

    在以下文件中删除 <fqname>ISecureElement/SIM2</fqname>

    • /device/mediatek/vendor/common/project_manifest/manifest_secure_element_dsds.xml
    • /device/mediatek/vendor/common/project_manifest/odm_manifest_secure_element_dsds.xml
  2. 修改HAL代码

    文件路径:/vendor/mediatek/proprietary/hardware/secure_element/MtkUiccSeService.cpp

    getNumberOfSim() 函数的逻辑修改为固定返回 1

    说明:此修改会使CTS只测试SIM1,从而避开对SIM2/eSIM的检测


方案三:必须支持OMAPI时的配置要求

📌 适用场景:业务要求必须支持OMAPI Feature

操作步骤

  1. 开启宏与服务

    • 配置 MTK_OMAPI_SUPPORT = yes
    • 确认 HAL service android.hardware.secure_element@1.2-service-mediatek 正常运行
  2. 使用合规测试卡

    • 实体卡槽必须插入CTS测试白卡
  3. eSIM Profile要求

    • 联系eSIM供应商,下载符合Google CTS测试要求的专用Profile

**三、**SecureElement XTS案例分析

Google针对SecureElement模块的XTS测试项还是非常多,本章介绍一下我在实际项目中遇到的一系列相关XTS问题,大概测试项如下:

1、CtsSecureElementTestCases

2、

相关推荐
齊家治國平天下4 小时前
Android 14 Vehicle HAL (VHAL) 设计与实现深度解析
android·aaos·carservice·车载开发·android 14·vhal·vehicle hal
AFinalStone10 小时前
Android 7系统网络(八)应用API层—ConnectivityManager使用与实战调试
android·网络
plainGeekDev11 小时前
kapt 替换为 KSP
android·java·kotlin
蜡台11 小时前
通过Gradle脚本声明更改Java变量
android·java·开发语言·python·kotlin·gradle·groovy
阿pin14 小时前
Android随笔-SharedPreferences
android·sp
阿pin15 小时前
Android随笔-DataStore
android·datastore
茶栀(*´I`*)15 小时前
Android 测试入门指南:ADB 基础配置与常用设备管理命令解析
android·adb
ihuyigui17 小时前
海外酒店预订短信接口
android·java·运维·服务器·前端·后端·架构
gxgldyh17 小时前
Android Framework源码解析(七):BootAnimation 启动流程解析——开机动画是如何显示出来的?
android
达达尼昂18 小时前
在 Claude Cowork 中用好 Claude Fable 5
android·人工智能·后端