本文基于Android6.0源码进行分析
源码分析
先从TelephonyManager
入手,如果想要监听手机的状态信息,需要调用TelephonyManager
的以下接口
private static ITelephonyRegistry sRegistry;
public void listen(PhoneStateListener listener, int events) {
if (mContext == null) return;
try {
Boolean notifyNow = (getITelephony() != null);
sRegistry.listenForSubscriber(listener.mSubId, getOpPackageName(),
listener.callback, events, notifyNow);
} catch (RemoteException ex) {
// system process dead
} catch (NullPointerException ex) {
// system process dead
}
}
实际上调用了sRegistry.listenForSubscriber()
方法,sRegistry
则是一个aidl接口
public TelephonyManager(Context context) {
Context appContext = context.getApplicationContext();
if (appContext != null) {
mContext = appContext;
} else {
mContext = context;
}
mSubscriptionManager = SubscriptionManager.from(mContext);
//TODO 获取ITelephonyRegistry
if (sRegistry == null) {
sRegistry = ITelephonyRegistry.Stub.asInterface(ServiceManager.getService(
"telephony.registry"));
}
}
通过查找源码可知,ITelephonyRegistry
实现类为
./frameworks/base/services/core/java/com/android/server/TelephonyRegistry.java
追踪listenForSubscriber
方法
@Override
public void listenForSubscriber(int subId, String pkgForDebug, IPhoneStateListener callback,
int events, boolean notifyNow) {
listen(pkgForDebug, callback, events, notifyNow, subId);
}
private void listen(String callingPackage, IPhoneStateListener callback, int events,
boolean notifyNow, int subId) {
int callerUserId = UserHandle.getCallingUserId();
if (VDBG) {
log("listen: E pkg=" + callingPackage + " events=0x" + Integer.toHexString(events)
+ " notifyNow=" + notifyNow + " subId=" + subId + " myUserId="
+ UserHandle.myUserId() + " callerUserId=" + callerUserId);
}
if (events != PhoneStateListener.LISTEN_NONE) {
/* Checks permission and throws Security exception */
checkListenerPermission(events);
if ((events & ENFORCE_PHONE_STATE_PERMISSION_MASK) != 0) {
try {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, null);
// SKIP checking for run-time permission since caller or self has PRIVILEGED
// permission
} catch (SecurityException e) {
if (mAppOps.noteOp(AppOpsManager.OP_READ_PHONE_STATE, Binder.getCallingUid(),
callingPackage) != AppOpsManager.MODE_ALLOWED) {
return;
}
}
}
synchronized (mRecords) {
// register
Record r;
find_and_add: {
IBinder b = callback.asBinder();
final int N = mRecords.size();
for (int i = 0; i < N; i++) {
r = mRecords.get(i);
if (b == r.binder) {
break find_and_add;
}
}
r = new Record();
r.binder = b;
mRecords.add(r);
if (DBG) log("listen: add new record");
}
r.callback = callback;
r.callingPackage = callingPackage;
r.callerUserId = callerUserId;
boolean isPhoneStateEvent = (events & (CHECK_PHONE_STATE_PERMISSION_MASK
| ENFORCE_PHONE_STATE_PERMISSION_MASK)) != 0;
r.canReadPhoneState = isPhoneStateEvent && canReadPhoneState(callingPackage);
// Legacy applications pass SubscriptionManager.DEFAULT_SUB_ID,
// force all illegal subId to SubscriptionManager.DEFAULT_SUB_ID
if (!SubscriptionManager.isValidSubscriptionId(subId)) {
r.subId = SubscriptionManager.DEFAULT_SUBSCRIPTION_ID;
} else {//APP specify subID
r.subId = subId;
}
r.phoneId = SubscriptionManager.getPhoneId(r.subId);
int phoneId = r.phoneId;
if(!validatePhoneId(phoneId)){
phoneId = 0;
}
r.events = events;
if (DBG) {
log("listen: Register r=" + r + " r.subId=" + r.subId + " phoneId=" + phoneId);
}
if (VDBG) toStringLogSSC("listen");
if (notifyNow && validatePhoneId(phoneId)) {
if ((events & PhoneStateListener.LISTEN_SERVICE_STATE) != 0) {
try {
if (VDBG) log("listen: call onSSC state=" + mServiceState[phoneId]);
r.callback.onServiceStateChanged(
new ServiceState(mServiceState[phoneId]));
} catch (RemoteException ex) {
remove(r.binder);
}
}
/* SPRD: Add for VoLTE @{ */
if ((events & PhoneStateListener.LISTEN_VOLTE_STATE) != 0) {
try {
if (VDBG) log("listen: mVoLteServiceState=" + mVoLteServiceState);
r.callback.onVoLteServiceStateChanged(
new VoLteServiceState(mVoLteServiceState));
} catch (RemoteException ex) {
remove(r.binder);
}
}
/* @} */
if ((events & PhoneStateListener.LISTEN_SIGNAL_STRENGTH) != 0) {
try {
int gsmSignalStrength = mSignalStrength[phoneId]
.getGsmSignalStrength();
r.callback.onSignalStrengthChanged((gsmSignalStrength == 99 ? -1
: gsmSignalStrength));
} catch (RemoteException ex) {
remove(r.binder);
}
}
if ((events & PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR) != 0) {
try {
r.callback.onMessageWaitingIndicatorChanged(
mMessageWaiting[phoneId]);
} catch (RemoteException ex) {
remove(r.binder);
}
}
if ((events & PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR) != 0) {
try {
r.callback.onCallForwardingIndicatorChanged(
mCallForwarding[phoneId]);
} catch (RemoteException ex) {
remove(r.binder);
}
}
if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_LOCATION)) {
try {
if (DBG_LOC) log("listen: mCellLocation = "
+ mCellLocation[phoneId]);
r.callback.onCellLocationChanged(
new Bundle(mCellLocation[phoneId]));
} catch (RemoteException ex) {
remove(r.binder);
}
}
if ((events & PhoneStateListener.LISTEN_CALL_STATE) != 0) {
try {
r.callback.onCallStateChanged(mCallState[phoneId],
getCallIncomingNumber(r, phoneId));
} catch (RemoteException ex) {
remove(r.binder);
}
}
if ((events & PhoneStateListener.LISTEN_DATA_CONNECTION_STATE) != 0) {
try {
r.callback.onDataConnectionStateChanged(mDataConnectionState[phoneId],
mDataConnectionNetworkType[phoneId]);
} catch (RemoteException ex) {
remove(r.binder);
}
}
if ((events & PhoneStateListener.LISTEN_DATA_ACTIVITY) != 0) {
try {
r.callback.onDataActivity(mDataActivity[phoneId]);
} catch (RemoteException ex) {
remove(r.binder);
}
}
if ((events & PhoneStateListener.LISTEN_SIGNAL_STRENGTHS) != 0) {
try {
r.callback.onSignalStrengthsChanged(mSignalStrength[phoneId]);
} catch (RemoteException ex) {
remove(r.binder);
}
}
if ((events & PhoneStateListener.LISTEN_OTASP_CHANGED) != 0) {
try {
r.callback.onOtaspChanged(mOtaspMode);
} catch (RemoteException ex) {
remove(r.binder);
}
}
if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_INFO)) {
try {
if (DBG_LOC) log("listen: mCellInfo[" + phoneId + "] = "
+ mCellInfo.get(phoneId));
r.callback.onCellInfoChanged(mCellInfo.get(phoneId));
} catch (RemoteException ex) {
remove(r.binder);
}
}
if ((events & PhoneStateListener.LISTEN_DATA_CONNECTION_REAL_TIME_INFO) != 0) {
try {
r.callback.onDataConnectionRealTimeInfoChanged(mDcRtInfo);
} catch (RemoteException ex) {
remove(r.binder);
}
}
if ((events & PhoneStateListener.LISTEN_PRECISE_CALL_STATE) != 0) {
try {
r.callback.onPreciseCallStateChanged(mPreciseCallState);
} catch (RemoteException ex) {
remove(r.binder);
}
}
if ((events & PhoneStateListener.LISTEN_PRECISE_DATA_CONNECTION_STATE) != 0) {
try {
r.callback.onPreciseDataConnectionStateChanged(
mPreciseDataConnectionState);
} catch (RemoteException ex) {
remove(r.binder);
}
}
if ((events & PhoneStateListener.LISTEN_CARRIER_NETWORK_CHANGE) != 0) {
try {
r.callback.onCarrierNetworkChange(mCarrierNetworkChangeState);
} catch (RemoteException ex) {
remove(r.binder);
}
}
}
}
} else {
if(DBG) log("listen: Unregister");
remove(callback.asBinder());
}
}
我们只关注APN的状态信息,具体看以下代码
private PreciseDataConnectionState mPreciseDataConnectionState = new PreciseDataConnectionState();
if ((events & PhoneStateListener.LISTEN_PRECISE_DATA_CONNECTION_STATE) != 0) {
try {
r.callback.onPreciseDataConnectionStateChanged(
mPreciseDataConnectionState);
} catch (RemoteException ex) {
remove(r.binder);
}
}
而mPreciseDataConnectionState
信息的更新,则是在notifyDataConnectionForSubscriber
方法,在./frameworks/base/telephony/java/android/telephony/PreciseDataConnectionState.java
中记录了,网络连接状态的一些信息
public class PreciseDataConnectionState implements Parcelable {
// 连接状态
private int mState = TelephonyManager.DATA_UNKNOWN;
// 网络类型
private int mNetworkType = TelephonyManager.NETWORK_TYPE_UNKNOWN;
// apn类型
private String mAPNType = "";
// apn名称
private String mAPN = "";
// 数据连接变化的原因
private String mReason = "";
// 网络链接属性
private LinkProperties mLinkProperties = null;
// 连接失败的原因
private String mFailCause = "";
// 省略代码。。。
}
最终,将状态信息回传到PhoneStateListener
中,在该类中,通过handler的方式,将数据进行处理分发
public PhoneStateListener(int subId, Looper looper) {
if (DBG) log("ctor: subId=" + subId + " looper=" + looper);
mSubId = subId;
mHandler = new Handler(looper) {
public void handleMessage(Message msg) {
if (DBG) {
log("mSubId=" + mSubId + " what=0x" + Integer.toHexString(msg.what)
+ " msg=" + msg);
}
switch (msg.what) {
case LISTEN_SERVICE_STATE:
PhoneStateListener.this.onServiceStateChanged((ServiceState)msg.obj);
break;
case LISTEN_SIGNAL_STRENGTH:
PhoneStateListener.this.onSignalStrengthChanged(msg.arg1);
break;
case LISTEN_MESSAGE_WAITING_INDICATOR:
PhoneStateListener.this.onMessageWaitingIndicatorChanged(msg.arg1 != 0);
break;
case LISTEN_CALL_FORWARDING_INDICATOR:
PhoneStateListener.this.onCallForwardingIndicatorChanged(msg.arg1 != 0);
break;
case LISTEN_CELL_LOCATION:
PhoneStateListener.this.onCellLocationChanged((CellLocation)msg.obj);
break;
case LISTEN_CALL_STATE:
PhoneStateListener.this.onCallStateChanged(msg.arg1, (String)msg.obj);
break;
case LISTEN_DATA_CONNECTION_STATE:
PhoneStateListener.this.onDataConnectionStateChanged(msg.arg1, msg.arg2);
PhoneStateListener.this.onDataConnectionStateChanged(msg.arg1);
break;
case LISTEN_DATA_ACTIVITY:
PhoneStateListener.this.onDataActivity(msg.arg1);
break;
case LISTEN_SIGNAL_STRENGTHS:
PhoneStateListener.this.onSignalStrengthsChanged((SignalStrength)msg.obj);
break;
case LISTEN_OTASP_CHANGED:
PhoneStateListener.this.onOtaspChanged(msg.arg1);
break;
case LISTEN_CELL_INFO:
PhoneStateListener.this.onCellInfoChanged((List<CellInfo>)msg.obj);
break;
case LISTEN_PRECISE_CALL_STATE:
PhoneStateListener.this.onPreciseCallStateChanged((PreciseCallState)msg.obj);
break;
//TODO 这里是需要关注的地方,当APN状态发生改变时,传递到这里
case LISTEN_PRECISE_DATA_CONNECTION_STATE:
PhoneStateListener.this.onPreciseDataConnectionStateChanged(
(PreciseDataConnectionState)msg.obj);
break;
case LISTEN_DATA_CONNECTION_REAL_TIME_INFO:
PhoneStateListener.this.onDataConnectionRealTimeInfoChanged(
(DataConnectionRealTimeInfo)msg.obj);
break;
case LISTEN_VOLTE_STATE:
PhoneStateListener.this.onVoLteServiceStateChanged((VoLteServiceState)msg.obj);
break;
case LISTEN_OEM_HOOK_RAW_EVENT:
PhoneStateListener.this.onOemHookRawEvent((byte[])msg.obj);
break;
case LISTEN_CARRIER_NETWORK_CHANGE:
PhoneStateListener.this.onCarrierNetworkChange((boolean)msg.obj);
break;
}
}
};
}
当APN状态发生改变是,会调用onPreciseDataConnectionStateChanged方法
/**
* Callback invoked when data connection state changes with precise information.
*
* @hide
*/
public void onPreciseDataConnectionStateChanged(
PreciseDataConnectionState dataConnectionState) {
// default implementation empty
}
但是该方法是被隐藏了的,我们是无法进行重写。但是可以通过private final Handler mHandler;
来进行一些处理,通过反射加载机制,可以了解到当final修饰的成员变量在定义的时候并没有初始化值的话,那么就还能通过java反射机制来动态修改它的值。那么就可以通过对该mHandler
属性进行修改,变成我们自定义的Handler,然后在我们自定义的Handler中接收数据的处理。
工具封装
简单使用
private ApnStateManager mApnStateManager;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mApnStateManager = ApnStateManager.getInstance();
mApnStateManager.register(this, mCallback);
}
@Override
protected void onDestroy() {
super.onDestroy();
mApnStateManager.unregister(mCallback);
}
private final ApnStateManager.Callback mCallback = new ApnStateManager.Callback() {
@Override
public void onStateChanged(ApnStateManager.ApnState state) {
//TODO 状态发生改变时,回调
Log.d(TAG, "onStateChanged: " + state.getDataConnectionAPN());
}
};
注意需要android.permission.READ_PRECISE_PHONE_STATE
,因为该权限是android:protectionLevel="signature|privileged"
级别,需要系统签名才可使用,如果想普通应用也有权限,则可以修改frameworks/base/core/res/AndroidManifest.xml
将signature|privileged
权限改为normal
即可。
ApnStateManager.java
package com.example.demoapn;
import android.content.Context;
import android.net.LinkProperties;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.annotation.RequiresPermission;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class ApnStateManager {
private final String TAG = getClass().getSimpleName();
private static final ApnStateManager INSTANCE = new ApnStateManager();
private List<Callback> mCallbacks = new ArrayList<>();
private TelephonyManager mTelephonyManager;
private Map<String, Field> mFields = new HashMap<>();
private ApnStateManager() {
}
public static ApnStateManager getInstance() {
return INSTANCE;
}
/**
* 注册监听,如果有注册,结束时请调用{@link ApnStateManager#unregister(Callback)}解除,否则可能导致内存泄漏
*
* @param context 上下文
* @param callback 监听回调{@link Callback}
*/
@RequiresPermission("android.permission.READ_PRECISE_PHONE_STATE")
public void register(Context context, Callback callback) {
if (mCallbacks.contains(callback)) {
return;
}
mCallbacks.add(callback);
if (null != mTelephonyManager) {
return;
}
mTelephonyManager = (TelephonyManager) context.getApplicationContext().getSystemService(Context.TELEPHONY_SERVICE);
if (null == mTelephonyManager) {
return;
}
try {
PhoneStateListener listener = new PhoneStateListener();
Field mHandler = PhoneStateListener.class.getDeclaredField("mHandler");
mHandler.setAccessible(true);
mHandler.set(listener, new Handler(Looper.getMainLooper()) {
@Override
public void handleMessage(@NonNull Message msg) {
handleApnState(msg.obj);
}
});
mTelephonyManager.listen(listener, 0x00001000);
} catch (NoSuchFieldException e) {
Log.e(TAG, "NoSuchFieldException: ", e);
} catch (IllegalAccessException e) {
Log.e(TAG, "IllegalAccessException: ", e);
}
}
private void handleApnState(Object obj) {
if (null == obj) {
return;
}
Class<?> cls = obj.getClass();
if (!"android.telephony.PreciseDataConnectionState".equals(cls.getName())) {
return;
}
if (mFields.size() == 0) {
Field[] fields = cls.getDeclaredFields();
for (Field field : fields) {
final String fieldName = field.getName();
if (!fieldName.startsWith("m")) {
continue;
}
field.setAccessible(true);
mFields.put(fieldName, field);
}
}
ApnState apnState = new ApnState();
Class<?> apnCls = ApnState.class;
for (Field field : mFields.values()) {
try {
final String fieldName = field.getName();
field.setAccessible(true);
Field newFiled = apnCls.getDeclaredField(fieldName);
newFiled.setAccessible(true);
newFiled.set(apnState, field.get(obj));
} catch (NoSuchFieldException e) {
Log.e(TAG, "NoSuchFieldException: ", e);
} catch (IllegalAccessException e) {
Log.e(TAG, "IllegalAccessException: ", e);
}
}
for (Callback callback : mCallbacks) {
callback.onStateChanged(apnState);
}
}
/**
* 解除注册,与{@link ApnStateManager#register(Context, Callback)}传入的Callback成对出现
*
* @param callback 监听回调{@link Callback}
*/
public void unregister(Callback callback) {
mCallbacks.remove(callback);
if (mCallbacks.size() == 0) {
mTelephonyManager.listen(null, 0x00001000);
mTelephonyManager = null;
}
}
public interface Callback {
void onStateChanged(ApnState state);
}
public static class ApnState {
private int mState = TelephonyManager.DATA_UNKNOWN;
private int mNetworkType = TelephonyManager.NETWORK_TYPE_UNKNOWN;
private String mAPNType = "";
private String mAPN = "";
private String mReason = "";
private LinkProperties mLinkProperties = null;
private String mFailCause = "";
/**
* Get data connection state
*
* @see TelephonyManager#DATA_UNKNOWN
* @see TelephonyManager#DATA_DISCONNECTED
* @see TelephonyManager#DATA_CONNECTING
* @see TelephonyManager#DATA_CONNECTED
* @see TelephonyManager#DATA_SUSPENDED
*/
public int getDataConnectionState() {
return mState;
}
/**
* Get data connection network type
*
* @see TelephonyManager#NETWORK_TYPE_UNKNOWN
* @see TelephonyManager#NETWORK_TYPE_GPRS
* @see TelephonyManager#NETWORK_TYPE_EDGE
* @see TelephonyManager#NETWORK_TYPE_UMTS
* @see TelephonyManager#NETWORK_TYPE_CDMA
* @see TelephonyManager#NETWORK_TYPE_EVDO_0
* @see TelephonyManager#NETWORK_TYPE_EVDO_A
* @see TelephonyManager#NETWORK_TYPE_1xRTT
* @see TelephonyManager#NETWORK_TYPE_HSDPA
* @see TelephonyManager#NETWORK_TYPE_HSUPA
* @see TelephonyManager#NETWORK_TYPE_HSPA
* @see TelephonyManager#NETWORK_TYPE_IDEN
* @see TelephonyManager#NETWORK_TYPE_EVDO_B
* @see TelephonyManager#NETWORK_TYPE_LTE
* @see TelephonyManager#NETWORK_TYPE_EHRPD
* @see TelephonyManager#NETWORK_TYPE_HSPAP
*/
public int getDataConnectionNetworkType() {
return mNetworkType;
}
/**
* Get data connection APN type
*/
public String getDataConnectionAPNType() {
return mAPNType;
}
/**
* Get data connection APN.
*/
public String getDataConnectionAPN() {
return mAPN;
}
/**
* Get data connection change reason.
*/
public String getDataConnectionChangeReason() {
return mReason;
}
/**
* Get the properties of the network link.
*/
public LinkProperties getDataConnectionLinkProperties() {
return mLinkProperties;
}
/**
* Get data connection fail cause, in case there was a failure.
*/
public String getDataConnectionFailCause() {
return mFailCause;
}
}
}