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、

相关推荐
一只特立独行的Yang2 小时前
Android Graphics - openGL and Vulkan小结
android
2501_915921433 小时前
在 Linux 上通过命令行上架 iOS APP,Fastlane + AppUploader(开心上架)
android·linux·运维·ios·小程序·uni-app·iphone
2501_915921433 小时前
从构建到 IPA 保护,Flutter iOS 包如何做混淆与安全处理
android·安全·flutter·ios·小程序·uni-app·iphone
2501_916008893 小时前
iPhone 手机硬件组件使用耗能历史记录查看,能耗查看
android·ios·智能手机·小程序·uni-app·iphone·webview
峥嵘life3 小时前
Android16 EDLA更新25-12补丁导致【CTS】CtsWindowManagerDeviceAnimations存在fail项
android·linux·学习
13 小时前
深度解析Compose中的BoxWithConstraints
android·kotlin·android jetpack
jolimark13 小时前
MySQL--》如何在MySQL中打造高效优化索引
android·mysql·adb
book123_0_9914 小时前
【MySQL】MySQL函数之JSON_EXTRACT
android·mysql·json
冬奇Lab14 小时前
ContentProvider与Uri权限:跨应用数据共享
android·源码阅读