分类目录归档:未分类

CCID接口规范

控制通道(Control pipe)
GET_DESCRIPTOR 和 SET_CONFIGURATION 等标准请求 通过此通道发送。

命令在默认通道上发动,报告信息也在默认通道上返还给主机。
———————–
中断通道处理异步事件
NotifySlotChange (卡插入,移除)
HardwareError (硬件错误)
————————
Bulk-in, Bulk-out通道

CCID命令在BULK_OUT端点 发送
每个命令都会有一个响应。有些响应可以立即得到。
有些响应 需要通过 BULK-IN 端口返回。

发送给指定卡槽的所有命令,都必须是同步发送的。
一个卡槽同一时刻,只能接受一个命令。
如果一个卡槽准备接受一个命令,那么就应该认为它是空闲的。

如果每条命令 都是给不同的空闲卡槽的,那么主机最多可以同时发送 bMaxCCIDBusySlots 条命令给 CCID
主机需要记住哪些slot是繁忙的。
当激活的卡槽数量达到 bMaxCCIDBusySlots时, CCID只能在 控制通道,接受 通用请求 或者 特定类的请求,去 ABORT一个slot

当CCID成功接收到一条给 繁忙卡槽的命令时,它应该报一个 CMD_SLOT_BUSY 错误

为了实现对每条命令的跟踪,主机对 发出的命令,设置一个 唯一的 bSeq 命令标识符。
CCID发回响应时,也要带上同样的 bSeq 标识符,表明 这条命令已经处理完毕。
驱动程序不会发送新的命令给 slot, 直到前面发送命令的 ending response响应被收到。
如果命令有错误或者超时, 那么 会发送 abandon/abort 类特定的命令 给 控制端点。

对于一个 BULK-OUT 命令 消息,可能会产生多个 BULK-IN 响应消息。
For example, the CCID can send a BULK-IN message with a Time Extension status to notify
the host that the ICC has requested more time to process the ICC command and, after a
delay, follow this with a second BULK-IN message with the ICC’s response to the
command. When this happens, both BULK-IN messages have the same bSeq value.

如果Bulk-In 消息的大小 是 MaxPacketSize 的倍数,那么应该在它后面还发一个 Zero Length Packet (ZLP)
ZLP包可以让 CCID设备驱动更有效率, 是一种最佳实践。

———————————————
CCID 发送 RDR_to_PC_NotifySlotChange 到主机, 通知驱动程序, 新插入了卡
收到驱动来的 PC_to_RDR_IccPowerOn 消息, CCID重新激活 IC卡

PC_to_RDR_IccPowerOn         RDR_to_PC_DataBlock
PC_to_RDR_IccPowerOff        RDR_to_PC_SlotStatus
PC_to_RDR_GetSlotStatus      RDR_to_PC_SlotStatus
PC_to_RDR_XfrBlock           RDR_to_PC_DataBlock
PC_to_RDR_GetParameters      RDR_to_PC_Parameters
PC_to_RDR_ResetParameters    RDR_to_PC_Parameters
PC_to_RDR_SetParameters      RDR_to_PC_Parameters
PC_to_RDR_Escape             RDR_to_PC_Escape
PC_to_RDR_IccClock           RDR_to_PC_SlotStatus
PC_to_RDR_T0APDU             RDR_to_PC_SlotStatus
PC_to_RDR_Secure             RDR_to_PC_DataBlock
PC_to_RDR_Mechanical         RDR_to_PC_SlotStatus
PC_to_RDR_Abort              RDR_to_PC_SlotStatus
PC_to_RDR_SetDataRateAndClockFrequency              RDR_to_PC_DataRateAndClockFrequency

CCID_PC_To_RDR Commands

CodeCommandDescriptionEquivalent PC/SC function
62PC_To_RDR_IccPowerOnPower up the card in the slot, and return its ATRSCardConnect
63PC_To_RDR_IccPowerOffPower down the card in the slotSCardDisconnect
65PC_To_RDR_GetSlotStatusRetrieve the slot’s current status and protocol dataSCardStatus
6BPC_To_RDR_EscapeSend a direct command to the deviceSCardControl
6FPC_To_RDR_XfrBlockSend a C-APDU to the card (and return its R-APDU)SCardTransmit

CCID_RDR_To_PC Responses

CodeCommandDescriptionIn response to
80RDR_To_PC_DataBlockR-APDU returned by the card
ATR of the card
PC_To_RDR_XfrBlock (success)
PC_To_RDR_IccPowerOn (success)
81RDR_To_PC_SlotStatusStatus of the slotPC_To_RDR_GetSlotStatus
PC_To_RDR_IccPowerOff
PC_To_RDR_XfrBlock (failure)
PC_To_RDR_IccPowerOn (failure)
83RDR_To_PC_EscapeSend a direct command to the devicePC_To_RDR_Escape

Smart card ATR parsing

在线分析

Smart card ATR parsing

源代码: https://github.com/LudovicRousseau/pyscard-contrib/tree/master/parseATR

https://android.googlesource.com/platform/frameworks/opt/telephony/+/master/src/java/com/android/internal/telephony/uicc/AnswerToReset.java

从ATR中就可以看出是否支持eUICC功能

TB(3) = 0x82 –> eUICC-related functions supported

3B 9F 96 80 3F C7 82 80 31 E0 73 FE 21 1B 63 3A 20 4E 83 00 90 00 31

3B 9F 97 80 3F C7 82 80 31 E0 73 FE 21 1F 64 08 63 62 00 82 90 00 6F

3B 9F 97 C0 0A 3F C7 82 80 31 E0 73 FE 21 1F 65 D0 02 1A 14 A2 81 0F CF

3B 9F 96 80 3F C7 82 80 31 E0 73 F6 21 57 57 4A 4D 02 0B 60 50 00 38

纯Python的Web UI

只需要懂Python就可以了,不再需要学习 JavaScript HTML CSS
NiceGUI

NiceGUI httpx coroutine button click

import asyncio
import httpx
from nicegui import ui


async def add(url):
    print('----')
    l = ui.label('This should be visible')


    async with httpx.AsyncClient() as client:
        r = await client.get(url)
        res = r.json()
        l.text = res['ip']


ip_url = 'https://api.seeip.org/jsonip'
#ip_url = 'https://api.ipify.org/?format=json'

ui.button('Add label', on_click= lambda:add(ip_url))

ui.run(reload=False,  host="::", port=5678, favicon='🚀', title='httpx协程') 

报错

 RuntimeWarning: coroutine 'add' was never awaited
  self.on('click', lambda _: handle_event(on_click, ClickEventArguments(sender=self, client=self.client)))
RuntimeWarning: Enable tracemalloc to get the object allocation traceback

修改成不带参数的

import asyncio
import httpx
from nicegui import ui



#ip_url = 'https://api.seeip.org/jsonip'
ip_url = 'https://api.bigdatacloud.net/data/client-ip'

async def add():
    print('----')
    l = ui.label('Waiting...')


    async with httpx.AsyncClient() as client:
        r = await client.get(ip_url)
        res = r.json()
        l.text = res['ipString']



ui.button('Get IP', on_click=add)

ui.run(reload=False,  host="::", port=5678, favicon='🚀', title='httpx协程') 

真有传递参数,还是有办法的

How to pass an argument to an async function with a ui.button

import asyncio
import httpx
from nicegui import ui
from functools import partial


ip_url = 'https://api.seeip.org/jsonip'
#ip_url = 'https://ipv6.jsonip.com/'
#  https://ipv4.jsonip.com/
#  http://no-tls.jsonip.com/

async def add(url):
    print('----')
    l = ui.label('Waiting...')

    async with httpx.AsyncClient() as client:
        r = await client.get(url)
        res = r.json()
        l.text = res['ip']

ui.button('Get IP', on_click=partial(add, ip_url))

ui.run(reload=False,  host="::", port=5678, favicon='🚀', title='httpx协程') 

就是用 functools 的 partial

SubscriptionManager

boolean setSubscriptionEnabled(int subscriptionId, boolean enable)
首先检查 canDisablePhysicalSubscription

public static int getSubscriptionId(int slotIndex)

boolean isSubscriptionEnabled(int subscriptionId)

public SubscriptionInfo getActiveSubscriptionInfoForSimSlotIndex (int slotIndex)

getSubscriptionId()

Jetpack Compose

@Composable
fun TextDemo() {
    Column(modifier = Modifier.fillMaxSize()) {
        var text by remember { mutableStateOf("Hello, World!") }
        Button(onClick = {


            text = "Good"
        }) {
            Text(text = "Go")
        }

        Text(text)
    }
}

点击button, 修改text

Android SIM卡pass through模式

将SIM卡先Power Down, 然后在Power up pass through, 就可以将 SIM设置为直通(pass through)模式.

当初sim卡处于直通模式时,modem不发送其他任何指令(包括选择MF文件,TERMINAL CAPABILITY)。sim卡完全被Telephony控制, 直接发送 APDU. SIM卡的状态,将被设置为RIL_CARDSTATE_PRESENT, card apps的数目将是0. 不会生成任何错误代码。紧急呼叫将被支持,就如同SIM不存在时,也可以支持紧急呼叫那样。

直通模式,只对 激活它的 特定会话 有效。当卡下次初始化时, 就回到普通模式,除非你 再次请求直通模式。也就是说,手机重启后, SIM卡将回到 正常模式。

调用者应该监视 TelephonyIntents#ACTION_SIM_STATE_CHANGED 广播,来决定 成功或者失败,以及是否超时. 但新设备上,不保证会触发 广播。 请用新接口 setSimPowerState(int, Executor, Consumer_integer)

回调可能的值:
SET_SIM_POWER_STATE_SUCCESS
SET_SIM_POWER_STATE_ALREADY_IN_STATE
SET_SIM_POWER_STATE_MODEM_ERROR
SET_SIM_POWER_STATE_SIM_ERROR
SET_SIM_POWER_STATE_NOT_SUPPORTED
如果请求的 sim卡状态不对,将抛出 IllegalArgumentException 异常。

platform/hardware/interfaces/+/master/radio/1.6/IRadio.hal

oneway setSimCardPower_1_6(int32_t serial, CardPowerState powerUp);
设置SIM卡电源状态。
请求关掉 或者打开 sim卡的电源。
它不应该生成一个 CardState.CARDSTATE_ABSEND指示。
因为SIM卡还是物理插入在卡槽的。

当SIM卡处于直通模式时, modem不发送任何指定给sim卡,(比如
SELECT MF或者TERMINAL CAPABILITY指令)。SIM卡完全被
Telephony控制发送APDU.
SIM卡的状态必须是 RIL_CAFDSTATE_PERSENT
卡上的apps数量将为0
不会生成新的错误代码。
在切换为POWER_UP/POWE_UP_PASS_THROUGH状态前,SIM卡必须处于power down.

在手机power up时, SIM卡接口也会自动power up
关sim,开sim,这些请求,必须等前一个请求完成后,才能处理。

关卡状态,在CardStatus.applicaont中, modem发送一个空的AppStatus向量。

在关卡状态是,如果物理移除并插入新的sim卡,新卡必须默认处于开卡状态。

oneway setSimCardPower_1_1(int32_t serial, CardPowerState powerUp);

hardware/interfaces/radio/aidl/android/hardware/radio/sim/IRadioSim.aidl
void setSimCardPower(in int serial, in CardPowerState powerUp);