2019独角兽企业重金招聘Python工程师标准>>>

PIN,全称Personal Identification Number,即个人识别码,用来认证使用者的身份。
当用户启用PIN后,手机在加载SIM卡时(开机或插卡)就会要求用户输入PIN,这时用户有3次输入PIN的机会,
但若3次都输入错误的话,就会要求输入PUK,即PIN Unlocking Key,PUK是PIN的解锁码,需要注意的是,
PUK总共只有10次输入机会,也就是说,只要输入了10次错误的PUK,该SIM卡就报废了,而这里所说的10次
并非指连续10次,而是只要输错一次,SIM卡内部计数器就减1,即使输入正确的PUK后,计数器的值也不会被
恢复,直到计数器减为0后,该卡报废。

PIN的种类
Universal PIN:多个Application共用一个PIN
Application PIN:Application自己的PIN
Local PIN:某个DF特有的PIN

手机在读取启用了PIN的SIM卡时,读到的状态为PIN,可通过如下的RIL log查看APPSTATE字段。
RILJ : [3775]< GET_SIM_STATUS IccCardState {CARDSTATE_PRESENT,PINSTATE_ENABLED_NOT_VERIFIED,num_apps=1,gsm_id=0{APPTYPE_USIM,APPSTATE_PIN,pin1=PINSTATE_ENABLED_NOT_VERIFIED,pin2=PINSTATE_ENABLED_NOT_VERIFIED},cdma_id=-1,ims_id=-1} [SUB0]
而APPSTATE在IccCardApplicationStatus.AppState进行了定义,一共有以下几种状态:
public enum AppState{
APPSTATE_UNKNOWN,
APPSTATE_DETECTED,
APPSTATE_PIN,
APPSTATE_PUK,
APPSTATE_SUBSCRIPTION_PERSO,
APPSTATE_READY;
}

由于之前在UICC开机初始化的流程中已经对卡状态上报流程进行了一些分析,因此我们在这里就只简单说明下。
首先,在IccCardProxy中会注册监听EVENT_ICC_LOCKED事件。

private void registerUiccCardEvents() {
......
if (mUiccApplication != null) {
......
mUiccApplication.registerForLocked(this, EVENT_ICC_LOCKED, null);
......
}
......
}

当modem上报PIN_LOCKED后,在UiccCardApplication.update()方法中,会执行通知监听者的操作。

public void update (IccCardApplicationStatus as, Context c, CommandsInterface ci) {
......
if (mAppState != oldAppState) {
......
notifyPinLockedRegistrantsIfNeeded(null);
......
}

然后就是在IccCardProxy中处理EVENT_ICC_LOCKED事件。

public void handleMessage(Message msg) {
......
case EVENT_ICC_LOCKED:
processLockedState();
break;
......
}

将ExternalState设置为PIN_REQUIRED,为啥叫ExternalState?我也不知道!

private void processLockedState() {
......
AppState appState = mUiccApplication.getState();
switch (appState) {
case APPSTATE_PIN:
mPinLockedRegistrants.notifyRegistrants();
setExternalState(State.PIN_REQUIRED);
break;
......
}

private void setExternalState(State newState) {
setExternalState(newState, false);
}

对于ICC_LOCKED这种状态,我们需要发送InternalIccStateChanged的广播,为啥又是Internal?跟ExternalState啥关系?不知道!

private void setExternalState(State newState, boolean override) {
......
// For locked states, we should be sending internal broadcast.
if (IccCardConstants.INTENT_VALUE_ICC_LOCKED.equals(getIccStateIntentString(mExternalState))) {
broadcastInternalIccStateChangedIntent(getIccStateIntentString(mExternalState),
getIccStateReason(mExternalState));
} else {
broadcastIccStateChangedIntent(getIccStateIntentString(mExternalState),
getIccStateReason(mExternalState));
}
......
}

我们来看看广播的内容,包含了ICC_STATE、LOCKED_REASON,以及PhoneId。

private void broadcastInternalIccStateChangedIntent(String value, String reason) {
......
Intent intent = new Intent(ACTION_INTERNAL_SIM_STATE_CHANGED);
intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING
| Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
intent.putExtra(PhoneConstants.PHONE_NAME_KEY, "Phone");
intent.putExtra(IccCardConstants.INTENT_KEY_ICC_STATE, value);
intent.putExtra(IccCardConstants.INTENT_KEY_LOCKED_REASON, reason);
intent.putExtra(PhoneConstants.PHONE_KEY, mPhoneId); // SubId may not be valid.
log("Sending intent ACTION_INTERNAL_SIM_STATE_CHANGED" + " for mPhoneId : " + mPhoneId);
ActivityManager.broadcastStickyIntent(intent, UserHandle.USER_ALL);
}
}

接下来我们再来看看接受广播的地方,在SubscriptionInfoUpdater中,
发送消息让Handler处理EVENT_SIM_LOCKED事件。
private final BroadcastReceiver sReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {

if (action.equals(TelephonyIntents.ACTION_SIM_STATE_CHANGED)) {
......
} else if (action.equals(IccCardProxy.ACTION_INTERNAL_SIM_STATE_CHANGED)) {
if (IccCardConstants.INTENT_VALUE_ICC_LOCKED.equals(simStatus)) {
String reason = intent.getStringExtra(
IccCardConstants.INTENT_KEY_LOCKED_REASON);
sendMessage(obtainMessage(EVENT_SIM_LOCKED, slotIndex, -1, reason));
......
}
logd("[Receiver]-");
}
};

public void handleMessage(Message msg) {
......
case EVENT_SIM_LOCKED:
handleSimLocked(msg.arg1, (String) msg.obj);
break;
......
}

接下来会去读取IccId。

private void handleSimLocked(int slotId, String reason) {
......
if (fileHandler != null) {
String iccId = mIccId[slotId];
if (iccId == null) {
logd("Querying IccId");
fileHandler.loadEFTransparent(IccConstants.EF_ICCID,
obtainMessage(EVENT_SIM_LOCKED_QUERY_ICCID_DONE,
new QueryIccIdUserObj(reason, slotId)));
......
}

读取完IccId后,会再发送广播TelephonyIntents.ACTION_SIM_STATE_CHANGED。

public void handleMessage(Message msg) {
switch (msg.what) {
case EVENT_SIM_LOCKED_QUERY_ICCID_DONE: {
......
broadcastSimStateChanged(slotId, IccCardConstants.INTENT_VALUE_ICC_LOCKED,
uObj.reason);
......
}

private void broadcastSimStateChanged(int slotId, String state, String reason) {
Intent i = new Intent(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
......
i.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
i.putExtra(PhoneConstants.PHONE_NAME_KEY, "Phone");
i.putExtra(IccCardConstants.INTENT_KEY_ICC_STATE, state);
i.putExtra(IccCardConstants.INTENT_KEY_LOCKED_REASON, reason);
SubscriptionManager.putPhoneIdAndSubIdExtra(i, slotId);
logd("Broadcasting intent ACTION_SIM_STATE_CHANGED " + state + " reason " + reason +
" for mCardIndex: " + slotId);
ActivityManager.broadcastStickyIntent(i, UserHandle.USER_ALL);
rebroadcastIntentsOnUnlock.put(slotId, i);
}

再往后就是SystemUI处理广播,然后弹出输入PIN的界面。
在KeyguardSimPinView中,当用户输入PIN并点击确定后,就会调用PhoneInterfaceManager.supplyPinReportResultForSubscriber()
将PIN发送给modem尝试解锁。

public int[] supplyPinReportResultForSubscriber(int subId, String pin) {
enforceModifyPermission();
final UnlockSim checkSimPin = new UnlockSim(getPhone(subId).getIccCard());
checkSimPin.start();
return checkSimPin.unlockSim(null, pin);
}

继续将请求发送给IccCard,完成后会处理SUPPLY_PIN_COMPLETE事件。

synchronized int[] unlockSim(String puk, String pin) {
......
Message callback = Message.obtain(mHandler, SUPPLY_PIN_COMPLETE);

if (puk == null) {
mSimCard.supplyPin(pin, callback);
} else {
......
}
......
}

而这里的IccCard是通过GsmCdmaPhone获取到的,实际上是一个IccCardProxy对象,
因此实际调用的方法是IccCardProxy的supplyPin().

public void supplyPin(String pin, Message onComplete) {
synchronized (mLock) {
if (mUiccApplication != null) {
mUiccApplication.supplyPin(pin, onComplete);
......
}

继续到UiccApplication处理,通过调用RIL的接口将PIN发送给modem。

public void supplyPin (String pin, Message onComplete) {
synchronized (mLock) {
mCi.supplyIccPinForApp(pin, mAid, mHandler.obtainMessage(EVENT_PIN1_PUK1_DONE,
onComplete));
}
}

modem返回的结果最终会到达PhoneInterfaceManager,并将结果返回给SystemUI。

public void handleMessage(Message msg) {
AsyncResult ar = (AsyncResult) msg.obj;
switch (msg.what) {
case SUPPLY_PIN_COMPLETE:
Log.d(LOG_TAG, "SUPPLY_PIN_COMPLETE");
synchronized (UnlockSim.this) {
mRetryCount = msg.arg1;
if (ar.exception != null) {
if (ar.exception instanceof CommandException &&
((CommandException)(ar.exception)).getCommandError()
== CommandException.Error.PASSWORD_INCORRECT) {
mResult = PhoneConstants.PIN_PASSWORD_INCORRECT;
} else {
mResult = PhoneConstants.PIN_GENERAL_FAILURE;
}
} else {
mResult = PhoneConstants.PIN_RESULT_SUCCESS;
}
mDone = true;
UnlockSim.this.notifyAll();
}
break;
}
}

而SIM卡解锁后,就会开始进行正常的初始化流程了。

转载于:https://my.oschina.net/igiantpanda/blog/2222648

SIM PIN Lock相关推荐

  1. android app unlock sim pin,android Sim卡锁定 pin解锁流程学习

    1.Android自帶的pin解鎖部份在framework/base/policy/src/com/android/internal/policy/impl/SimUnlockScreen.java ...

  2. SIM相关术语MCC MNC UIM SIM PIN PUK简介

    MCC:移动国家号码,由3位数字组成,唯一地识别移动用户所属的国家. MNC:移动网号,由两位数字组成,用于识别移动用户所归属的移动网. IMSI:区别移动用户的标志,储存在SIM卡中,可用于区别移动 ...

  3. AndroidTelephony学习大纲

    2019独角兽企业重金招聘Python工程师标准>>> 移动通信基础知识     3gpp Phone     Phone状态监听     Phone相关类:CallNotifier ...

  4. 电话拦截以及电话拦截后的提示音

    1. 电话拦截 这个功能大家可能都知道了,就是利用反射原理调用ITelephony的隐藏方法来实现.这个就不说了,在附件的代码里有. 2.拦截后提示忙音/空号/已关机/已停机 这个功能其实是要用到MM ...

  5. 31、通信卫士--拦截黑名单电话

    当黑名单号码打进来时,自动挂断,并且在通话历史记录中删除该条记录. 挂断电话的操作可以通过PackageManager对象来实现,但是在android1.5以后,该方法没有暴露出来,需要通过AIDL来 ...

  6. Android电话拦截及拦截提示音的实现

    本文所讲的内容是在Android系统中如何写程序进行 电话拦截,并发出拦截提示音提醒用户,可以说此功能还是比较实用的. 1.电话拦截 这个功能大家可能都知道了,就是利用反射原理调用ITelephony ...

  7. android 电话监听和拦截

    一.首先在manifest.xml文件中获取监听电话权限,注册监听电话的Activity 1.添加访问手机电话状态的权限 <uses-permission android:name=" ...

  8. android电话拦截

    其实大家可以下载 xxx卫士看下,它设置来电拒接模式后,都是会启动设置MMI指令的界面.然后再去"设置->通话设置->来电转接",看看 "占线时转接" ...

  9. Android之电话拦截

    今天来和大家一起分享一下我最近写的一个Demo,类似于黑名单访问,也就是我们俗称的电话拦截 首先我们需要两个aidl文件 第一个:NeighboringCellInfo.aidl package an ...

最新文章

  1. 图像像素点赋值_医学图像处理教程(五)——医学图像边缘检测算法
  2. FastStone Capture
  3. ITK:可视化静态稀疏Whitaker 2D水平设置图层
  4. XML解析——Jsoup解析器
  5. apt-get常用命令及工作原理
  6. css 百分比 怎么固定正方形_css样式写出三角形,宽高自适应的正方形,扇形!...
  7. b站2020用户画像_B站2020年度动画大选来袭!论引战,还是要看B站
  8. 给Emacs安装一个脚踏板: 用Windows/Menu键作为key modifier
  9. python判断键盘输入_python实时检测键盘输入函数的示例
  10. 数据分析EXCEL常用统计函数
  11. 杰理之串口1使用固定引脚的配置方法【篇】
  12. texstudio暗色主题
  13. css定位“十字架“之水平垂直居中
  14. Python 把两张图片拼起来
  15. 常见问题及解决方法1
  16. photoshop下载安装_如何保存,共享,下载和安装自定义Photoshop操作
  17. 服务器系统通用串行总线控制器,win7进入设备管理器发现无法启动通用串行总线控制器如何解决...
  18. Cadence 如何通过.dra(封装)查看使用哪个.pad(焊盘)文件
  19. 超实时性单目标跟踪网络——Siamese RPN(CVPR2018 spotlight论文)
  20. js阻止默认事件(a标签跳转),阻止事件冒泡

热门文章

  1. Open-E DSS V7 应用系列之六 构建软件iSCSI
  2. 基础环境搭建--原始mavenWeb项目
  3. ⑤Windows Server 8 RemoteFX体验
  4. VSC 1.0 (netapp存储在vSphere vCenter 4上的插件)
  5. CentOS yum源
  6. 用tar来备份Ubuntu操作系统
  7. MultipartResolver实现文件上传功能
  8. NumPy Essentials 带注释源码 三、NumPy 数组使用
  9. PCB设计要点-DDR3布局布线技巧及注意事项
  10. Apache多站点设定