Emergency Call 分析
来源:互联网 发布:大腕精神病预言 知乎 编辑:程序博客网 时间:2024/05/22 09:03
outgoing call 有三类, 分别用三种intent 去标记 三种intent 定义如下
* This method will handle three kinds of actions: * * - CALL (action for usual outgoing voice calls) * - CALL_PRIVILEGED (can come from built-in apps like contacts / voice dialer / bluetooth) * - CALL_EMERGENCY (from the EmergencyDialer that's reachable from the lockscreen.)
紧急电话的几种调用方式
拨打Emergency call 是不需要卡的。应该走的是一种特殊的链路。
Emergency call 被两种Intent所触发(Intent.ACTION_CALL_EMERGENCY 和 Intent.ACTION_CALL_PRIVILEGED). CALL_PRIVILEGED是被系统级的应用所发起的,而CALL_EMERGENCY Intent 是从紧急呼叫的拨号盘里发起的,就是手机在没有SIM卡的模式下显示的拨号盘。CALL_PRIVILEGED这个intent 接到后会检查号码是否是emergency number, 如果是紧急电话的号码就会把intent的action 替换为ACTION_CALL_EMERGENCY, 如果不是就替换成ACTION_CALL。由此可看,虽然我们有三种call的intent action, 但是我们实际有效果的就是上述两种。CALL_PRIVILEGED这种action的call的作用的是能把紧急电话的号码带给phone app去处理,而普通的call action的intent是不可以的。processIntent实现里用一个flag变量callNow来控制是否拨打电话, callNow在满足拨打emengency call的时候被置为true,正常call会被在startSipCallOptionHandler 这里到类SipCallOptionHandler去处理。 3rd App是没有权限拨打Emergency call的, 如果3rd App在发起一个Intent.ACTION_CALL里带有Emergency number,会被阻止.OutgoingCallBroadcaster 类里的processIntent函数承担这部分的主要工作。 下面是google的代码
526 if (Intent.ACTION_CALL.equals(action)) {527 if (isPotentialEmergencyNumber) {528 Log.w(TAG, "Cannot call potential emergency number '" + number529 + "' with CALL Intent " + intent + ".");530 Log.i(TAG, "Launching default dialer instead...");531532 Intent invokeFrameworkDialer = new Intent();533534 // TwelveKeyDialer is in a tab so we really want535 // DialtactsActivity. Build the intent 'manually' to536 // use the java resolver to find the dialer class (as537 // opposed to a Context which look up known android538 // packages only)539 final Resources resources = getResources();540 invokeFrameworkDialer.setClassName(541 resources.getString(R.string.ui_default_package),542 resources.getString(R.string.dialer_default_class));543 invokeFrameworkDialer.setAction(Intent.ACTION_DIAL);544 invokeFrameworkDialer.setData(intent.getData());545 if (DBG) Log.v(TAG, "onCreate(): calling startActivity for Dialer: "546 + invokeFrameworkDialer);547 startActivity(invokeFrameworkDialer);548 finish();549 return;550 }551 callNow = false;拨打紧急电话与modem的互动关系
我们所注意到的是在拨打紧急电话的时候,当我们发现是一个紧急电话并且modem 在power off的模式下,会开启一个消息队列去开启modem startEmergencyCallFromAirplaneModeSequence这里面会有个timeout 的操作, 如果modem超时没有被开启,还会等待modem开启中, 继续往这个队列里放入消息。TIME_BETWEEN_RETRIES = 5000; // msec
具体的实现关键点中发现timeout这个retry机制是发一个timeout的消息到队列里去处理 sendEmptyMessageDelayed(RETRY_TIMEOUTTIME_BETWEEN_RETRIES);
timeout 的时间是5s ,类EmergencyCallHelper承担这部分消息处理的逻辑以及收到消息后采取的措施,是继续开启modem还是拨打紧急电话。第三方应用是不能影响,阻止拨打紧急电话的。
不论是紧急电话还是正常的电话,第三方应用是在系统中拨出一个电话后是可以接到ACTION_NEW_OUTGOING_CALL 这样的一个intent的,SIP call除外; 系统中拨打的电话包括contacts / voice dialer / bluetooth / dialer这里理解的系统中拨的电话就是上面所说的拨打电话中在code中调用到的CALL_PRIVILEGED 和 CALL_EMERGENCY这两种Intent。 但不同的是紧急电话不能被阻止,常规的号码是可以被第三方阻止的,第三方应该可以会接到这样一个通知。紧急电话是直接播出去后再发这个intent.
目前SIP call还不能被第三方拦截,也就是说上面提到的拨打一个SIP call之后直接return, 不会再去发一个ACTION_NEW_OUTGOING_CALL给外部,google在代码注释上写未来需要支持。在processIntent的实现里用一个flag变量callNo来控制是否拨打电话, callNow在满足拨打emengency call的时候被置为true,正常call会被在startSipCallOptionHandler 这里到类SipCallOptionHandler去处理。具体实现参照packages/services/Telephony/src/com/android/phone/OutgoingCallBroadcaster.java424 private void processIntent(Intent intent) {425 if (DBG) {426 Log.v(TAG, "processIntent() = " + intent + ", thread: " + Thread.currentThread());427 }428 final Configuration configuration = getResources().getConfiguration();429430 // Outgoing phone calls are only allowed on "voice-capable" devices.431 if (!PhoneGlobals.sVoiceCapable) {432 Log.i(TAG, "This device is detected as non-voice-capable device.");433 handleNonVoiceCapable(intent);434 return;435 }436437 String action = intent.getAction();438 String number = PhoneNumberUtils.getNumberFromIntent(intent, this);439 // Check the number, don't convert for sip uri440 // TODO put uriNumber under PhoneNumberUtils441 if (number != null) {442 if (!PhoneNumberUtils.isUriNumber(number)) {443 number = PhoneNumberUtils.convertKeypadLettersToDigits(number);444 number = PhoneNumberUtils.stripSeparators(number);445 }446 } else {447 Log.w(TAG, "The number obtained from Intent is null.");448 }449450 AppOpsManager appOps = (AppOpsManager)getSystemService(Context.APP_OPS_SERVICE);451 int launchedFromUid;452 String launchedFromPackage;453 try {454 launchedFromUid = ActivityManagerNative.getDefault().getLaunchedFromUid(455 getActivityToken());456 launchedFromPackage = ActivityManagerNative.getDefault().getLaunchedFromPackage(457 getActivityToken());458 } catch (RemoteException e) {459 launchedFromUid = -1;460 launchedFromPackage = null;461 }462 if (appOps.noteOp(AppOpsManager.OP_CALL_PHONE, launchedFromUid, launchedFromPackage)463 != AppOpsManager.MODE_ALLOWED) {464 Log.w(TAG, "Rejecting call from uid " + launchedFromUid + " package "465 + launchedFromPackage);466 finish();467 return;468 }469470 // If true, this flag will indicate that the current call is a special kind471 // of call (most likely an emergency number) that 3rd parties aren't allowed472 // to intercept or affect in any way. (In that case, we start the call473 // immediately rather than going through the NEW_OUTGOING_CALL sequence.)474 boolean callNow;475476 if (getClass().getName().equals(intent.getComponent().getClassName())) {477 // If we were launched directly from the OutgoingCallBroadcaster,478 // not one of its more privileged aliases, then make sure that479 // only the non-privileged actions are allowed.480 if (!Intent.ACTION_CALL.equals(intent.getAction())) {481 Log.w(TAG, "Attempt to deliver non-CALL action; forcing to CALL");482 intent.setAction(Intent.ACTION_CALL);483 }484 }485486 // Check whether or not this is an emergency number, in order to487 // enforce the restriction that only the CALL_PRIVILEGED and488 // CALL_EMERGENCY intents are allowed to make emergency calls.489 //490 // (Note that the ACTION_CALL check below depends on the result of491 // isPotentialLocalEmergencyNumber() rather than just plain492 // isLocalEmergencyNumber(), to be 100% certain that we *don't*493 // allow 3rd party apps to make emergency calls by passing in an494 // "invalid" number like "9111234" that isn't technically an495 // emergency number but might still result in an emergency call496 // with some networks.)497 final boolean isExactEmergencyNumber =498 (number != null) && PhoneNumberUtils.isLocalEmergencyNumber(number, this);499 final boolean isPotentialEmergencyNumber =500 (number != null) && PhoneNumberUtils.isPotentialLocalEmergencyNumber(number, this);501 if (VDBG) {502 Log.v(TAG, " - Checking restrictions for number '" + number + "':");503 Log.v(TAG, " isExactEmergencyNumber = " + isExactEmergencyNumber);504 Log.v(TAG, " isPotentialEmergencyNumber = " + isPotentialEmergencyNumber);505 }506507 /* Change CALL_PRIVILEGED into CALL or CALL_EMERGENCY as needed. */508 // TODO: This code is redundant with some code in InCallScreen: refactor.509 if (Intent.ACTION_CALL_PRIVILEGED.equals(action)) {510 // We're handling a CALL_PRIVILEGED intent, so we know this request came511 // from a trusted source (like the built-in dialer.) So even a number512 // that's *potentially* an emergency number can safely be promoted to513 // CALL_EMERGENCY (since we *should* allow you to dial "91112345" from514 // the dialer if you really want to.)515 if (isPotentialEmergencyNumber) {516 Log.i(TAG, "ACTION_CALL_PRIVILEGED is used while the number is a potential"517 + " emergency number. Use ACTION_CALL_EMERGENCY as an action instead.");518 action = Intent.ACTION_CALL_EMERGENCY;519 } else {520 action = Intent.ACTION_CALL;521 }522 if (DBG) Log.v(TAG, " - updating action from CALL_PRIVILEGED to " + action);523 intent.setAction(action);524 }525 当第三方App去拨打紧急电话时,会launch一个缺省的dialer然后直接return.也不会再去发Intent.ACTION_NEW_OUTGOING_CALL intent给外部使用526 if (Intent.ACTION_CALL.equals(action)) {527 if (isPotentialEmergencyNumber) {528 Log.w(TAG, "Cannot call potential emergency number '" + number529 + "' with CALL Intent " + intent + ".");530 Log.i(TAG, "Launching default dialer instead...");531532 Intent invokeFrameworkDialer = new Intent();533534 // TwelveKeyDialer is in a tab so we really want535 // DialtactsActivity. Build the intent 'manually' to536 // use the java resolver to find the dialer class (as537 // opposed to a Context which look up known android538 // packages only)539 final Resources resources = getResources();540 invokeFrameworkDialer.setClassName(541 resources.getString(R.string.ui_default_package),542 resources.getString(R.string.dialer_default_class));543 invokeFrameworkDialer.setAction(Intent.ACTION_DIAL);544 invokeFrameworkDialer.setData(intent.getData());545 if (DBG) Log.v(TAG, "onCreate(): calling startActivity for Dialer: "546 + invokeFrameworkDialer);547 startActivity(invokeFrameworkDialer);548 finish();549 return;550 }551 callNow = false;552 } else if (Intent.ACTION_CALL_EMERGENCY.equals(action)) {553 // ACTION_CALL_EMERGENCY case: this is either a CALL_PRIVILEGED554 // intent that we just turned into a CALL_EMERGENCY intent (see555 // above), or else it really is an CALL_EMERGENCY intent that556 // came directly from some other app (e.g. the EmergencyDialer557 // activity built in to the Phone app.)558 // Make sure it's at least *possible* that this is really an559 // emergency number.560 if (!isPotentialEmergencyNumber) {561 Log.w(TAG, "Cannot call non-potential-emergency number " + number562 + " with EMERGENCY_CALL Intent " + intent + "."563 + " Finish the Activity immediately.");564 finish();565 return;566 }567 callNow = true;568 } else {569 Log.e(TAG, "Unhandled Intent " + intent + ". Finish the Activity immediately.");570 finish();571 return;572 }573574 // Make sure the screen is turned on. This is probably the right575 // thing to do, and more importantly it works around an issue in the576 // activity manager where we will not launch activities consistently577 // when the screen is off (since it is trying to keep them paused578 // and has... issues).579 //580 // Also, this ensures the device stays awake while doing the following581 // broadcast; technically we should be holding a wake lock here582 // as well.583 PhoneGlobals.getInstance().wakeUpScreen();584585 // If number is null, we're probably trying to call a non-existent voicemail number,586 // send an empty flash or something else is fishy. Whatever the problem, there's no587 // number, so there's no point in allowing apps to modify the number.588 if (TextUtils.isEmpty(number)) {589 if (intent.getBooleanExtra(EXTRA_SEND_EMPTY_FLASH, false)) {590 Log.i(TAG, "onCreate: SEND_EMPTY_FLASH...");591 PhoneUtils.sendEmptyFlash(PhoneGlobals.getPhone());592 finish();593 return;594 } else {595 Log.i(TAG, "onCreate: null or empty number, setting callNow=true...");596 callNow = true;597 }598 }599600 if (callNow) {601 // This is a special kind of call (most likely an emergency number)602 // that 3rd parties aren't allowed to intercept or affect in any way.603 // So initiate the outgoing call immediately.604605 Log.i(TAG, "onCreate(): callNow case! Calling placeCall(): " + intent);606607 // Initiate the outgoing call, and simultaneously launch the608 // InCallScreen to display the in-call UI:609 PhoneGlobals.getInstance().callController.placeCall(intent);610611 // Note we do *not* "return" here, but instead continue and612 // send the ACTION_NEW_OUTGOING_CALL broadcast like for any613 // other outgoing call. (But when the broadcast finally614 // reaches the OutgoingCallReceiver, we'll know not to615 // initiate the call again because of the presence of the616 // EXTRA_ALREADY_CALLED extra.)617 }618619 // For now, SIP calls will be processed directly without a620 // NEW_OUTGOING_CALL broadcast.621 //622 // TODO: In the future, though, 3rd party apps *should* be allowed to623 // intercept outgoing calls to SIP addresses as well. To do this, we should624 // (1) update the NEW_OUTGOING_CALL intent documentation to explain this625 // case, and (2) pass the outgoing SIP address by *not* overloading the626 // EXTRA_PHONE_NUMBER extra, but instead using a new separate extra to hold627 // the outgoing SIP address. (Be sure to document whether it's a URI or just628 // a plain address, whether it could be a tel: URI, etc.)629 Uri uri = intent.getData();630 String scheme = uri.getScheme();631 if (Constants.SCHEME_SIP.equals(scheme) || PhoneNumberUtils.isUriNumber(number)) {632 Log.i(TAG, "The requested number was detected as SIP call.");633 startSipCallOptionHandler(this, intent, uri, number);634 finish();635 return;636637 // TODO: if there's ever a way for SIP calls to trigger a638 // "callNow=true" case (see above), we'll need to handle that639 // case here too (most likely by just doing nothing at all.)640 }641 当去拨打一个电话(紧急电话或常规号码,不包括SIP call)后,暴露给外部一个ACTION_NEW_OUTGOING_CALL的intent642 Intent broadcastIntent = new Intent(Intent.ACTION_NEW_OUTGOING_CALL);643 if (number != null) {644 broadcastIntent.putExtra(Intent.EXTRA_PHONE_NUMBER, number);645 }646 CallGatewayManager.checkAndCopyPhoneProviderExtras(intent, broadcastIntent);647 broadcastIntent.putExtra(EXTRA_ALREADY_CALLED, callNow);648 broadcastIntent.putExtra(EXTRA_ORIGINAL_URI, uri.toString());649 // Need to raise foreground in-call UI as soon as possible while allowing 3rd party app650 // to intercept the outgoing call.651 broadcastIntent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);652 if (DBG) Log.v(TAG, " - Broadcasting intent: " + broadcastIntent + ".");653654 // Set a timer so that we can prepare for unexpected delay introduced by the broadcast.655 // If it takes too much time, the timer will show "waiting" spinner.656 // This message will be removed when OutgoingCallReceiver#onReceive() is called before the657 // timeout.658 mHandler.sendEmptyMessageDelayed(EVENT_OUTGOING_CALL_TIMEOUT,659 OUTGOING_CALL_TIMEOUT_THRESHOLD);660 sendOrderedBroadcastAsUser(broadcastIntent, UserHandle.OWNER,661 PERMISSION, new OutgoingCallReceiver(),662 null, // scheduler663 Activity.RESULT_OK, // initialCode664 number, // initialData: initial value for the result data665 null); // initialExtras666 }
0 0
- Emergency Call 分析
- Emergency Call 分析 (Android 4.4 R1)
- Android Emergency Call 号码
- emergency call number
- android tips—启动Emergency call拨号盘
- Emergency
- emergency
- Emergency
- Emergency
- Emergency
- 解决:Android4.3锁屏界面Emergency calls only - China Unicom与EMERGENCY CALL语义重复
- Can't make emergency call without SIM card
- android M Power Button three times Make Emergency Call
- System call 的分析
- 6572 Phone call分析
- Call分析(一)
- Why It’s Better to Text Than Call in a Mass Emergency
- Android Call分析(一) ---- Call对象详解
- fragment 创建菜单注意事项
- qt: exec()的用法,accept()和accepted的概念
- 微信支付页面不显示以及空白页error -1
- svn检出数据无法验证问题解决方法
- windows编程经典书籍
- Emergency Call 分析
- Ubuntu安装到跑起Tomcat全套教程
- Java多线程Synchronized心得
- 贪心理论
- 【新资讯】ZABBIX 3.2.0alpha1发布
- 计算机基础一之导论篇
- [转载]浅谈Linux的内存管理机制
- /usr/sap 或者 /sapmnt目录被日志撑满,删除JOB LOG的方法
- C++ typedef用法小结 (※不能不看※)