Android4.4 RIL上报网络状态服务变化

388 阅读7分钟

一、前言

手机插入SIM卡并成功启动后,BP Modem会读取SIM卡中的IMSI(International Mobile Subscriber Identification Number,国际移动用户识别码)信息完成SIM卡中信息的验证和电信运营商移动网络的注册,这样手机才能使用电信运营商提供的网络服务,如接打电话、发送接收短彩信、手机上网等服务

二、ServiceStateTracker介绍

Telephony Frameworks框架层中,ServiceStateTracker对象主要管理网络服务的基本信息,有着非常重要的作用。 ServiceStateTracker抽象类与CallTracker相同,共继承了Handler类,其实质是自定义的Handler消息处理类 GsmServiceStateTrackerCdmaServiceStateTracker分别继承和实现了ServiceStateTracker

三、ServiceStateTracker到RIL流程

GsmServiceStateTracker在构造方法中会注册Handler消息,该类在上次视频中PhoneGloabas初始化构建Phone对象时执行

// frameworks\opt\telephony\src\java\com\android\internal\telephony\gsm\GsmServiceStateTracker.java

public GsmServiceStateTracker(GSMPhone phone) {
		// Handler消息注册
    mCi.registerForAvailable(this, EVENT_RADIO_AVAILABLE, null);
    mCi.registerForRadioStateChanged(this, EVENT_RADIO_STATE_CHANGED, null);

    mCi.registerForVoiceNetworkStateChanged(this, EVENT_NETWORK_STATE_CHANGED, null);
    mCi.setOnNITZTime(this, EVENT_NITZ_TIME, null);
    mCi.setOnRestrictedStateChanged(this, EVENT_RESTRICTED_STATE_CHANGED, null);
    mCi.registerForPSStateChanged(this,EVENT_PS_STATE_CHANGED, null);
}

servicestateTracker到RIL流程.png

  1. GsmServiceStateTracker的构造方法中,通过registerForXXX()setOnXXX()完成不同的Handler消息注册
  2. 手机启动完成并成功注册网络后,RIL层会发出EVENT_SIM_READY类型的 Handler消息通知,ServiceStateTracker对象调用 handleMessage()方法完成此消息的接收,接着调用 pollState()方法响应此消息。
  3. 会在pollState()方法中向RIL对象发出4个关于网络服务的查询请求,包括
    1. 获取注册的运营商网络信息
    2. 获取注册的数据连接类型
    3. 获取注册的语音通话网络类型
    4. 获取网络类型
  4. RIL 完成发起的查询最新网络服务的信息和状态后,通过ServiceStateTracker对象创建的Message对象发起Callback回调,到GsmServiceStateTrackerhandleMessage()中去处理,最后到handlePollStateResult(),将查询出来的当前最新的网络服务信息和状态更新和保存在ServiceStateTracker对象的多个属性中。
  5. 所有消息都处理完成后,最后在pollStateDone()完成处理查询网络服务相关信息结果的收尾工作
    1. 通过当前状态和新的状态获取服务信息改变的标志
    2. 更新sscellLoc对象信息,同时更新一些gprsStatemMaxDataCallsmRadioTechnology等属性,此外,重置newSSnewCellLoc等对象的值
    3. 发出网络服务状态信息变化的消息通知

最终会比对当前的状态和新查询的结果进行比对,当发现不同有变化时,会调用mPhone.notifyXX()向上通知

四、手机状态栏信号实时变化

1. GsmServiceStateTracker处理

在待机界面的状态栏可以观察到手机信号的变化,其实这里的手机信号实时变化,准确来说应该是准实时变化,是由GsmServiceStateTracker对象通过Handler.sendMessageDelay定时向RIL对象发起查询手机接入无线网络的信号量值,然后发起信号量变化通知,通知栏应用收到信号量变化消息通知后,从而更新手机接入的网络信号图标。

首先进入GsmServiceStateTracker.java代码文件,手机开机后,SIM 卡准备完成,RIL层发出 EVENT_SIM_READY通知,GsmServiceStateTracker 对象进入 handleMessage() 方法接收和响应此消息;接着调用当前类的 queueNextSignalStrengthPoll()方法,向RIL对象查询手机信号量,其代码详情如下:

// frameworks\opt\telephony\src\java\com\android\internal\telephony\gsm\GsmServiceStateTracker.java

private void queueNextSignalStrengthPoll() {
		...
    Message msg;
    msg = obtainMessage();
    msg.what = EVENT_POLL_SIGNAL_STRENGTH;

    // TODO Don't poll signal strength if screen is off
		// 延时发送,在ServiceStateTracker定义为20* 1000ms,即20s
    sendMessageDelayed(msg, POLL_PERIOD_MILLIS);
}

因为父类ServiceStateTracker也是继承的Handler,因此,20s后会在handleMessage接收并响应该消息:

// frameworks\opt\telephony\src\java\com\android\internal\telephony\gsm\GsmServiceStateTracker.java

case EVENT_POLL_SIGNAL_STRENGTH:
      // Just poll signal strength...not part of pollState()
      mCi.getSignalStrength(obtainMessage(EVENT_GET_SIGNAL_STRENGTH));
      break;

RIL完成最新的信号量查询后,通过Callback消息对象发起Handler消息通知,GsmServiceStateTracker对象中的handleMessage()方法会接收和响应此消息通知,处理如下:

// frameworks\opt\telephony\src\java\com\android\internal\telephony\gsm\GsmServiceStateTracker.java

case EVENT_GET_SIGNAL_STRENGTH:
      // This callback is called when signal strength is polled
      // all by itself

      if (!(mCi.getRadioState().isOn())) {
          // Polling will continue when radio turns back on
          return;
      }
      ar = (AsyncResult) msg.obj;
      onSignalStrengthResult(ar, true);
      queueNextSignalStrengthPoll();

      break;

接着在onSignalStrengthResult() 根据查询的结果更新和保存最新的信号量相关信息,完成后再次调用queueNextSignalStrengthPoll() 等待下一次查询

# frameworks\opt\telephony\src\java\com\android\internal\telephony\gsm\GsmServiceStateTracker.java

protected boolean onSignalStrengthResult(AsyncResult ar, boolean isGsm) {
    SignalStrength oldSignalStrength = mSignalStrength;

    // This signal is used for both voice and data radio signal so parse
    // all fields

    if ((ar.exception == null) && (ar.result != null)) {
        mSignalStrength = (SignalStrength) ar.result;
        mSignalStrength.validateInput();
        mSignalStrength.setGsm(isGsm);
    } else {
        log("onSignalStrengthResult() Exception from RIL : " + ar.exception);
        mSignalStrength = new SignalStrength(isGsm);
    }

    return notifySignalStrength();
}

![[GsmServiceStateTracker和RIL通信.png]] 手机成功启动并注册到电信运营商网络后,RIL层会发起EVENT_SIM_READY的消息通知,在 GsmServiceStateTracker对象中接收到此消息后,便开始循环调用queueNextSignalStrengthPoll() 方法,将结果通过mCi.get完成手机接入电信运营商网络的无线信号量查询,其流程如上图所示。

2.GsmServiceStateTracker通知给APP

Pasted image 20241117233956.png

  1. 从右边看起,NetworkControllerAPP SystemUI的一个类,它持有TelephonyManager,调用了listen方法,而TelephonyManager持有ITelephonyRegistry这个接口,调用了它的listen方法

网络上报流程.png ITelephonyRegistry是一个AIDL文件,用来跨进程通信使用的,TelephonyRegistry实现了它的所有方法,注意到这个类中有个mRecordsArrayList,用来保存我们的监听对象

  1. GsmServiceStateTracker继承了抽象类ServiceStateTracker

    GsmServiceStateTracker会收到RIL发过来的信号强度消息,调用父类的notifySignalStrength()方法,

    ServiceStateTracker持有PhoneBase的对象mPhoneBasePhoneBase中也有自己的notifySignalStrength方法,并且PhoneBase持有PhoneNotifier接口,而DefaultPhoneNotifierPhoneNotifier的实现类,会实现notifySignalStrength方法,并且DefaultPhoneNotifier 也持有ITelephonyRegistry,调用它的notifySignalStrength(),里面会遍历mRecords这个List,把具体的消息发送给监听者,这样APP就可以收到消息,刷新显示出来了

  2. 所以其实就是一个通过aidl进行的跨进程通信,listen 负责把监听者添加保存起来,notifyXXX()方法负责把消息通知遍历给所有的监听器的过程

3. 代码分析

1. SystemUI注册网络信号监听的

  1. NetworkController中的构造方法中,会设置PhoneStateListener监听器,监听从Telephony Framework返回的网络状态变化
// frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
   
   public NetworkController(Context context) {
   		// telephony
       mPhone = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
       for (int i=0; i < mPhoneCount; i++) {
           mPhone.listen(getPhoneStateListener(i),
                             PhoneStateListener.LISTEN_SERVICE_STATE
                           | PhoneStateListener.LISTEN_SIGNAL_STRENGTHS
                           | PhoneStateListener.LISTEN_CALL_STATE
                           | PhoneStateListener.LISTEN_DATA_CONNECTION_STATE
                           | PhoneStateListener.LISTEN_DATA_ACTIVITY);
       }
   }
  1. TelephonyManagerlisten方法中开始监听,可以看到是通过sRegistry继续监听,而sRegistry 是通过sRegistry = ITelephonyRegistry.Stub.asInterface(ServiceManager.getService("telephony.registry")); IBinder类型的service转化为ITelephonyRegistry类型对象,然后就可以调用ITelephonyRegistry的方法了
   public void listen(PhoneStateListener listener, int events) {
       String pkgForDebug = mContext != null ? mContext.getPackageName() : "<unknown>";
       try {
           Boolean notifyNow = true;
           /*modify by yuanhaobo for L1860_Req00000163 @ 2014-02-16 begin*/
           if (getStandbyCount() > 1) {
               if (-1 == listener.mLinkId) {
                   for (int linkId = 0; linkId < getStandbyCount(); linkId++) {
                       sRegistry.listenMSMS(pkgForDebug, listener.callback, events, notifyNow, linkId);
                   }
               } else {
                   sRegistry.listenMSMS(pkgForDebug, listener.callback, events, notifyNow, listener.mLinkId);
               }
           } else {
               sRegistry.listen(pkgForDebug, listener.callback, events, notifyNow);
           }
           /*modify by yuanhaobo for L1860_Req00000163 @ 2014-02-16 end*/
       } catch (RemoteException ex) {
           // system process dead
       } catch (NullPointerException ex) {
           // system process dead
       }
   }
   
   public TelephonyManager(Context context) {
       Context appContext = context.getApplicationContext();
       if (appContext != null) {
           mContext = appContext;
       } else {
           mContext = context;
       }
   
       if (sRegistry == null) {
           sRegistry = ITelephonyRegistry.Stub.asInterface(ServiceManager.getService(
                   "telephony.registry"));
       }
   }

2. ServiceStateTracker通知

ServiceStateTracker.javaonSignalStrengthResult()收到信号消息后,到notifySignalStrength()

// frameworks/opt/telephony/src/java/com/android/internal/telephony/ServiceStateTracker.java
protected boolean notifySignalStrength() {
    boolean notified = false;
    synchronized(mCellInfo) {
        if (!mSignalStrength.equals(mLastSignalStrength)) {
            try {
                mPhoneBase.notifySignalStrength();
                notified = true;
            } catch (NullPointerException ex) {
                loge("updateSignalStrength() Phone already destroyed: " + ex
                     + "SignalStrength not notified");
            }
        }
    }
    return notified;
}
// frameworks/opt/telephony/src/java/com/android/internal/telephony/PhoneBase.java
public void notifySignalStrength() {
    mNotifier.notifySignalStrength(this);
}

mNotifier 是在PhoneGlobals.java#onCreate() 方法中,在PhoneFactory.java#makeDefaultPhone() 方法产生的

// frameworks/opt/telephony/src/java/com/android/internal/telephony/PhoneFactory.java
public static void makeDefaultPhone(Context context) {
		sPhoneNotifier = new DefaultPhoneNotifier();
		...
		int phoneType = TelephonyManager.getPhoneType(networkMode);
    if (phoneType == PhoneConstants.PHONE_TYPE_GSM) {
        Rlog.i(LOG_TAG, "Creating GSMPhone");

        sProxyPhone = new PhoneProxy(new GSMPhone(context,
                sCommandsInterface, sPhoneNotifier, false, 0), 0);

        sProxyPhoneList.add(0, sProxyPhone);
}

sPhoneNotifier在创建Phone时通过新建DefaultPhoneNotifier对象,传入到GSMPhone,也就是PhoneBase中的mNotifier ,在DefaultPhoneNotifier就可以看到notifySignalStrength()方法了,在它的构造方法中可以看到获取了ITelephonyRegistry对象

// frameworks/opt/telephony/src/java/com/android/internal/telephony/DefaultPhoneNotifier.java
protected DefaultPhoneNotifier() {
    mRegistry = ITelephonyRegistry.Stub.asInterface(ServiceManager.getService(
                "telephony.registry"));
}

@Override
public void notifySignalStrength(Phone sender) {
    try {
        mRegistry.notifySignalStrength(sender.getSignalStrength(), sender.getLinkID());
    } catch (RemoteException ex) {
        // system process is dead
    }
}

SystemServer启动时建立了telephonyRegistry对象,并通过ServiceManager添加了进去,之后就可以通过getService()的方式获取到TelephonyRegistry

// frameworks/base/services/java/com/android/server/SystemServer.java

public void initAndLoop(){
		TelephonyRegistry telephonyRegistry = null;
		telephonyRegistry = new TelephonyRegistry(context);
		ServiceManager.addService("telephony.registry", telephonyRegistry);
}

即调用了TelephonyRegistry中的notifySignalStrength()

// frameworks/base/services/java/com/android/server/TelephonyRegistry.java
public void notifySignalStrength(SignalStrength signalStrength) {
    notifySignalStrength(signalStrength, SimRouter.getDefaultPSSim(mContext));
}

public void notifySignalStrength(SignalStrength signalStrength, int linkId) {
    if (!checkNotifyPermission("notifySignalStrength()")) {
        return;
    }
    /*merge by yuanhaobo from L1813 @ 2013-11-29 begin*/
    synchronized (mRecords) {
        mSignalStrength[linkId] = signalStrength;
        for (Record r : mRecords) {
            if (((r.events & PhoneStateListener.LISTEN_SIGNAL_STRENGTHS) != 0)
                && (r.linkId == linkId)) {
                try {
                    r.callback.onSignalStrengthsChanged(new SignalStrength(signalStrength));
                } catch (RemoteException ex) {
                    mRemoveList.add(r.binder);
                }
            }
            if (((r.events & PhoneStateListener.LISTEN_SIGNAL_STRENGTH) != 0)
                && (r.linkId == linkId)) {
                try {
                    int gsmSignalStrength = signalStrength.getGsmSignalStrength();
                    r.callback.onSignalStrengthChanged((gsmSignalStrength == 99 ? -1
                            : gsmSignalStrength));
                } catch (RemoteException ex) {
                    mRemoveList.add(r.binder);
                }
            }
        }
        handleRemoveListLocked();
    }
    broadcastSignalStrengthChanged(signalStrength, linkId);
}

最后再看一下流程图:

网络上报流程.png