监听APN状态

本文基于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.xmlsignature|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;
        }

    }

}
上一篇:深度学习论文笔记


下一篇:微信小程序开发:学习笔记[8]——页面跳转及传参