telephony的监听注册机制

11 阅读7分钟

两层架构:

-   内部 `RegistrantList` 用于框架内快速同步通知
-   外部 `TelephonyRegistry` 用于应用层跨进程异步通知

Android Telephony 监听注册机制详解

Android Telephony 框架使用了一套优雅且高效的观察者模式实现,通过 RegistrantRegistrantList 提供了强大的事件通知机制。这是整个电信框架内部通信的基石。


一、核心类设计

1. Registrant (单个注册者)

public class Registrant
{
    @UnsupportedAppUsage
    public
    Registrant(Handler h, int what, Object obj)
    {
        refH = new WeakReference(h);
        this.what = what;
        userObj = obj;
    }

    @UnsupportedAppUsage
    public void
    clear()
    {
        refH = null;
        userObj = null;
    }

    @UnsupportedAppUsage
    public void
    notifyRegistrant()
    {
        internalNotifyRegistrant (null, null);
    }

    @UnsupportedAppUsage
    public void
    notifyResult(Object result)
    {
        internalNotifyRegistrant (result, null);
    }

    public void
    notifyException(Throwable exception)
    {
        internalNotifyRegistrant (null, exception);
    }

    /**
     * This makes a copy of @param ar
     */
    @UnsupportedAppUsage
    public void
    notifyRegistrant(AsyncResult ar)
    {
        internalNotifyRegistrant (ar.result, ar.exception);
    }

    /*package*/ void
    internalNotifyRegistrant (Object result, Throwable exception)
    {
        Handler h = getHandler();

        if (h == null) {
            clear();
        } else {
            Message msg = Message.obtain();

            msg.what = what;
            msg.obj = new AsyncResult(userObj, result, exception);
            h.sendMessage(msg);
        }
    }

    /**
     * NOTE: May return null if weak reference has been collected
     */

    @UnsupportedAppUsage
    public Message
    messageForRegistrant()
    {
        Handler h = getHandler();

        if (h == null) {
            clear();

            return null;
        } else {
            Message msg = h.obtainMessage();

            msg.what = what;
            msg.obj = userObj;

            return msg;
        }
    }

    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
    public Handler
    getHandler()
    {
        if (refH == null)
            return null;

        return (Handler) refH.get();
    }

    WeakReference   refH;
    int             what;
    Object          userObj;
}

关键特性:

  1. 弱引用 Handler

    WeakReference refH;
    
    • 避免内存泄漏
    • 如果 Handler 所属的对象被回收,自动失效
  2. 三要素:

    • refH: Handler 的弱引用
    • what: 消息类型码(Message.what)
    • userObj: 用户自定义对象
  3. 通知机制:

    msg.what = what;
    msg.obj = new AsyncResult(userObj, result, exception);
    h.sendMessage(msg);
    
    • 构造 Message,封装 AsyncResult
    • 通过 Handler 发送到目标线程

2. RegistrantList (注册者列表)

public class RegistrantList
{
    ArrayList   registrants = new ArrayList();      // of Registrant

    @UnsupportedAppUsage
    public RegistrantList() {
    }

    @UnsupportedAppUsage
    public synchronized void
    add(Handler h, int what, Object obj)
    {
        add(new Registrant(h, what, obj));
    }

    @UnsupportedAppUsage
    public synchronized void
    addUnique(Handler h, int what, Object obj)
    {
        // if the handler is already in the registrant list, remove it
        remove(h);
        add(new Registrant(h, what, obj));
    }

    @UnsupportedAppUsage
    public synchronized void
    add(Registrant r)
    {
        removeCleared();
        registrants.add(r);
    }

    @UnsupportedAppUsage
    public synchronized void
    removeCleared()
    {
        for (int i = registrants.size() - 1; i >= 0 ; i--) {
            Registrant  r = (Registrant) registrants.get(i);

            if (r.refH == null) {
                registrants.remove(i);
            }
        }
    }

    public synchronized void removeAll() {
        registrants.clear();
    }

    @UnsupportedAppUsage
    public synchronized int
    size()
    {
        return registrants.size();
    }

    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
    public synchronized Object
    get(int index)
    {
        return registrants.get(index);
    }

    private synchronized void
    internalNotifyRegistrants (Object result, Throwable exception)
    {
       for (int i = 0, s = registrants.size(); i < s ; i++) {
            Registrant  r = (Registrant) registrants.get(i);
            r.internalNotifyRegistrant(result, exception);
       }
    }

    @UnsupportedAppUsage
    public /*synchronized*/ void
    notifyRegistrants()
    {
        internalNotifyRegistrants(null, null);
    }

    public /*synchronized*/ void
    notifyException(Throwable exception)
    {
        internalNotifyRegistrants (null, exception);
    }

    @UnsupportedAppUsage
    public /*synchronized*/ void
    notifyResult(Object result)
    {
        internalNotifyRegistrants (result, null);
    }


    @UnsupportedAppUsage
    public /*synchronized*/ void
    notifyRegistrants(AsyncResult ar)
    {
        internalNotifyRegistrants(ar.result, ar.exception);
    }

    @UnsupportedAppUsage
    public synchronized void
    remove(Handler h)
    {
        for (int i = 0, s = registrants.size() ; i < s ; i++) {
            Registrant  r = (Registrant) registrants.get(i);
            Handler     rh;

            rh = r.getHandler();

            /* Clean up both the requested registrant and
             * any now-collected registrants
             */
            if (rh == null || rh == h) {
                r.clear();
            }
        }

        removeCleared();
    }
}

关键方法:

  1. add() vs addUnique()

    • add(): 允许同一 Handler 多次注册
    • addUnique(): 先移除已存在的,确保唯一性
  2. removeCleared()

    • 清理已失效的 Registrant (WeakReference 被回收)
    • 自动垃圾清理机制
  3. notifyRegistrants()

    • 遍历所有注册者
    • 逐个通知

二、典型使用模式

1. 声明 RegistrantList

    protected final RegistrantList mPreciseCallStateRegistrants = new RegistrantList();

    private final RegistrantList mHandoverRegistrants = new RegistrantList();

    private final RegistrantList mNewRingingConnectionRegistrants = new RegistrantList();

    private final RegistrantList mIncomingRingRegistrants = new RegistrantList();

    protected final RegistrantList mDisconnectRegistrants = new RegistrantList();

    private final RegistrantList mServiceStateRegistrants = new RegistrantList();

    protected final RegistrantList mMmiCompleteRegistrants = new RegistrantList();

    @UnsupportedAppUsage
    protected final RegistrantList mMmiRegistrants = new RegistrantList();

    protected final RegistrantList mUnknownConnectionRegistrants = new RegistrantList();

    protected final RegistrantList mSuppServiceFailedRegistrants = new RegistrantList();

    protected final RegistrantList mRadioOffOrNotAvailableRegistrants = new RegistrantList();

    protected final RegistrantList mSimRecordsLoadedRegistrants = new RegistrantList();

    private final RegistrantList mVideoCapabilityChangedRegistrants = new RegistrantList();

    protected final RegistrantList mEmergencyCallToggledRegistrants = new RegistrantList();

    private final RegistrantList mCellInfoRegistrants = new RegistrantList();

    private final RegistrantList mRedialRegistrants = new RegistrantList();

    private final RegistrantList mPhysicalChannelConfigRegistrants = new RegistrantList();

    private final RegistrantList mOtaspRegistrants = new RegistrantList();

    private final RegistrantList mPreferredNetworkTypeRegistrants = new RegistrantList();

Phone 类中的典型 RegistrantList:

  • 服务状态变化
  • 来电通知
  • 连接断开
  • MMI 命令
  • 信号强度
  • 小区信息
  • ...

2. 注册接口

    public void registerForVoiceRoamingOn(Handler h, int what, Object obj) {
        Registrant r = new Registrant(h, what, obj);
        mVoiceRoamingOnRegistrants.add(r);

        if (mSS.getVoiceRoaming()) {
            r.notifyRegistrant();
        }
    }

    public void unregisterForVoiceRoamingOn(Handler h) {
        mVoiceRoamingOnRegistrants.remove(h);
    }

    /**
     * Registration point for roaming off of mobile voice
     * combined roaming is true when roaming is true and ONS differs SPN
     *
     * @param h handler to notify
     * @param what what code of message when delivered
     * @param obj placed in Message.obj
     */
    public void registerForVoiceRoamingOff(Handler h, int what, Object obj) {
        Registrant r = new Registrant(h, what, obj);
        mVoiceRoamingOffRegistrants.add(r);

        if (!mSS.getVoiceRoaming()) {
            r.notifyRegistrant();
        }
    }

标准模式:

public void registerForXxxChanged(Handler h, int what, Object obj) {
    Registrant r = new Registrant(h, what, obj);
    mXxxRegistrants.add(r);
    
    // 立即通知当前状态(可选)
    if (currentState满足条件) {
        r.notifyRegistrant();
    }
}

public void unregisterForXxxChanged(Handler h) {
    mXxxRegistrants.remove(h);
}

3. 触发通知

    private void notifyCdmaSubscriptionInfoReady() {
        if (mCdmaForSubscriptionInfoReadyRegistrants != null) {
            if (DBG) log("CDMA_SUBSCRIPTION: call notifyRegistrants()");
            mCdmaForSubscriptionInfoReadyRegistrants.notifyRegistrants();
        }
    }

通知方式:

  1. 无参数通知:

    mRegistrants.notifyRegistrants();
    
  2. 携带结果:

    mRegistrants.notifyResult(result);
    
  3. 携带 AsyncResult:

    AsyncResult ar = new AsyncResult(null, result, exception);
    mRegistrants.notifyRegistrants(ar);
    

三、完整示例:网络驻网状态监听

1. 定义 RegistrantList (ServiceStateTracker)

private final RegistrantList mNetworkAttachedRegistrants = new RegistrantList();
private final RegistrantList mNetworkDetachedRegistrants = new RegistrantList();

2. 提供注册接口

    public void registerForNetworkAttached(Handler h, int what, Object obj) {
        Registrant r = new Registrant(h, what, obj);

        mNetworkAttachedRegistrants.add(r);
        if (mSS.getState() == ServiceState.STATE_IN_SERVICE) {
            r.notifyRegistrant();
        }
    }

    public void unregisterForNetworkAttached(Handler h) {
        mNetworkAttachedRegistrants.remove(h);
    }

    /**
     * Registration point for transition into network detached.
     * @param h handler to notify
     * @param what what code of message when delivered
     * @param obj in Message.obj
     */
    public void registerForNetworkDetached(Handler h, int what, Object obj) {
        Registrant r = new Registrant(h, what, obj);

        mNetworkDetachedRegistrants.add(r);
        if (mSS.getState() != ServiceState.STATE_IN_SERVICE) {
            r.notifyRegistrant();
        }
    }

    public void unregisterForNetworkDetached(Handler h) {
        mNetworkDetachedRegistrants.remove(h);
    }

特点: 注册时立即检查当前状态,如果已满足条件则立即通知

3. 监听者注册 (示例:DisplayInfoController)

// DisplayInfoController.java
private static final int EVENT_SERVICE_STATE_CHANGED = 1;

public DisplayInfoController(Phone phone) {
    mPhone = phone;
    // 注册服务状态变化监听
    mPhone.getServiceStateTracker()
        .registerForServiceStateChanged(this, EVENT_SERVICE_STATE_CHANGED, null);
}

@Override
public void handleMessage(Message msg) {
    switch (msg.what) {
        case EVENT_SERVICE_STATE_CHANGED:
            AsyncResult ar = (AsyncResult) msg.obj;
            ServiceState ss = (ServiceState) ar.result;
            // 处理服务状态变化
            updateDisplayInfo(ss);
            break;
    }
}

4. 触发通知

// ServiceStateTracker.java
private void pollStateDone() {
    // ... 状态检查
    
    if (hasNetworkAttached) {
        mNetworkAttachedRegistrants.notifyRegistrants();
    }
    
    if (hasNetworkDetached) {
        mNetworkDetachedRegistrants.notifyRegistrants();
    }
}

四、高级特性

1. Phone 切换时的迁移 (migrateFrom)

    protected void migrate(RegistrantList to, RegistrantList from) {
        if (from == null) {
            // May be null in some cases, such as testing.
            return;
        }
        from.removeCleared();
        for (int i = 0, n = from.size(); i < n; i++) {
            Registrant r = (Registrant) from.get(i);
            Message msg = r.messageForRegistrant();
            // Since CallManager has already registered with both CS and IMS phones,
            // the migrate should happen only for those registrants which are not
            // registered with CallManager.Hence the below check is needed to add
            // only those registrants to the registrant list which are not
            // coming from the CallManager.
            if (msg != null) {
                if (msg.obj == CallManager.getInstance().getRegistrantIdentifier()) {
                    continue;
                } else {
                    to.add((Registrant) from.get(i));
                }
            } else {

应用场景:

  • GSM ↔ CDMA 切换
  • SRVCC (CS 域切换)
  • Phone 对象替换

过程:

  1. 清理已失效的 Registrant
  2. 遍历源列表
  3. 排除特定注册者(如 CallManager)
  4. 迁移到新列表

2. 条件通知 (notifyNow)

    public void registerForCarrierAction(int action, Handler h, int what, Object obj,
                                         boolean notifyNow) {
        Boolean carrierAction = getCarrierActionEnabled(action);
        if (carrierAction == null) {
            throw new IllegalArgumentException("invalid carrier action: " + action);
        }
        RegistrantList list = getRegistrantsFromAction(action);
        Registrant r = new Registrant(h, what, obj);
        list.add(r);
        if (notifyNow) {
            r.notifyRegistrant(new AsyncResult(null, carrierAction, null));
        }
    }

特点:

  • notifyNow=true: 注册后立即通知当前状态
  • 避免错过状态

3. 多传输类型支持

    public void registerForDataConnectionAttached(@TransportType int transport, Handler h, int what,
                                                  Object obj) {
        Registrant r = new Registrant(h, what, obj);
        if (mAttachedRegistrants.get(transport) == null) {
            mAttachedRegistrants.put(transport, new RegistrantList());
        }
        mAttachedRegistrants.get(transport).add(r);

        if (mSS != null) {
            NetworkRegistrationInfo netRegState = mSS.getNetworkRegistrationInfo(
                    NetworkRegistrationInfo.DOMAIN_PS, transport);
            if (netRegState == null || netRegState.isInService()) {
                r.notifyRegistrant();
            }
        }
    }

设计:

private SparseArray<RegistrantList> mAttachedRegistrants = new SparseArray<>();
  • 使用 SparseArray<RegistrantList> 管理多种传输类型
  • WWAN (蜂窝网络)
  • WLAN (Wi-Fi)

五、设计优势

1. 内存安全

  • 弱引用: 自动避免内存泄漏
  • removeCleared(): 自动清理失效注册者

2. 线程安全

  • Handler 机制: 通过 Message 在目标线程执行
  • synchronized: RegistrantList 的关键方法同步

3. 解耦设计

  • 事件发布者无需知道监听者细节
  • 监听者可动态添加/移除
  • 支持多对多关系

4. 灵活性

  • 支持携带自定义数据 (userObj)
  • 支持携带结果和异常 (AsyncResult)
  • 支持立即通知当前状态

5. 高效

  • ArrayList 遍历性能高
  • 弱引用自动清理,无需手动管理
  • 批量通知高效

六、与标准观察者模式对比

特性Registrant 机制标准 Observer 模式
Handler 集成✓ 内置 Handler 支持✗ 需自行实现
线程安全✓ Message 机制跨线程✗ 需额外处理
内存管理✓ WeakReference 自动✗ 需手动清理
异常传递✓ AsyncResult 封装✗ 通常不支持
立即通知✓ 注册时可选通知✗ 通常不支持
数据携带✓ userObj + result✓ 通常支持

七、实战:自定义事件监听

假设要为 DataConnection 添加状态监听:

// 1. 声明 RegistrantList
private final RegistrantList mDataStateChangedRegistrants = new RegistrantList();

// 2. 提供注册接口
public void registerForDataStateChanged(Handler h, int what, Object obj) {
    Registrant r = new Registrant(h, what, obj);
    mDataStateChangedRegistrants.add(r);
    
    // 立即通知当前状态
    r.notifyResult(getCurrentState());
}

public void unregisterForDataStateChanged(Handler h) {
    mDataStateChangedRegistrants.remove(h);
}

// 3. 状态变化时通知
private void notifyDataStateChanged(int newState) {
    mDataStateChangedRegistrants.notifyResult(newState);
}

// 4. 监听者使用
class MyController extends Handler {
    private static final int EVENT_DATA_STATE_CHANGED = 1;
    
    public void init(DataConnection dc) {
        dc.registerForDataStateChanged(this, EVENT_DATA_STATE_CHANGED, null);
    }
    
    @Override
    public void handleMessage(Message msg) {
        if (msg.what == EVENT_DATA_STATE_CHANGED) {
            AsyncResult ar = (AsyncResult) msg.obj;
            int state = (Integer) ar.result;
            // 处理状态变化
        }
    }
}

八、总结

Android Telephony 的监听注册机制是一个精心设计的事件分发系统:

  1. 核心组件:

    • Registrant: 单个监听者封装
    • RegistrantList: 监听者列表管理
    • AsyncResult: 统一结果封装
  2. 关键特性:

    • 弱引用自动内存管理
    • Handler 机制保证线程安全
    • 支持立即通知当前状态
    • 支持异常和结果传递
  3. 广泛应用:

    • Phone 状态监听
    • ServiceState 变化
    • 数据连接状态
    • SIM 卡事件
    • 信号强度
    • ...

这套机制是整个 Android Telephony 框架的神经系统,连接了从底层 RIL 到上层 Framework 的所有组件!