TIF 和Hdmi cec hotplug热插拔事件过程梳理二

这次梳理下Hdmi设备增删的事件是如何传递到TvInputService,以及TvInputManagerService的处理差异。

1.HdmiCecLocalDeviceTv

HdmiControlService在收到HdmiCecController的onHotplug回调后,会再依次调用设备列表中的各个HdmiCecLocalDevice的onHotplug方法。以Tv为例,它会发起HotplugDetectionAction来轮询cec总线上的每一个逻辑地址,来判断是否需要添加或者删除设备。

Z:\p\frameworks\base\services\core\java\com\android\server\hdmi\HdmiCecLocalDeviceTv.java

    @Override
    @ServiceThreadOnly
    void onHotplug(int portId, boolean connected) {
        assertRunOnServiceThread();
        if (!connected) {
            removeCecSwitches(portId);
        }
        // Tv device will have permanent HotplugDetectionAction.
        List<HotplugDetectionAction> hotplugActions = getActions(HotplugDetectionAction.class);
        if (!hotplugActions.isEmpty()) {
            // Note that hotplug action is single action running on a machine.
            // "pollAllDevicesNow" cleans up timer and start poll action immediately.
            // It covers seq #40, #43.
            hotplugActions.get(0).pollAllDevicesNow();
        } else {
            HdmiLogger.debug("start poll devices for hotplug");
            addAndStartAction(new HotplugDetectionAction(HdmiCecLocalDeviceTv.this));
        }
    }

2.HotplugDetectionAction

Z:\p\frameworks\base\services\core\java\com\android\server\hdmi\HotplugDetectionAction.java

    private void pollAllDevices() {
        Slog.v(TAG, "Poll all devices.");

        pollDevices(new DevicePollingCallback() {
            @Override
            public void onPollingFinished(List<Integer> ackedAddress) {
                checkHotplug(ackedAddress, false);
            }
        }, Constants.POLL_ITERATION_IN_ORDER
                | Constants.POLL_STRATEGY_REMOTES_DEVICES, HdmiConfig.HOTPLUG_DETECTION_RETRY);
    }

addDevice是通过发送GET_PHSYCAL_ADDRESS message收到响应后再添加的。

    private void addDevice(int addedAddress) {
        // Sending <Give Physical Address> will initiate new device action.
        sendCommand(HdmiCecMessageBuilder.buildGivePhysicalAddress(getSourceAddress(),
                addedAddress));
    }

tv handleReportPhysicalAddress 

        HdmiDeviceInfo deviceInfo = new HdmiDeviceInfo(address, path, getPortId(path), type,
                Constants.UNKNOWN_VENDOR_ID, HdmiUtils.getDefaultDeviceName(address));
        addCecDevice(deviceInfo);

下面就是关键addCecDevice,这里会调用注册在HdmiControlService里面的IHdmiDeviceEventListener来触发DEVICE_EVENT_ADD_DEVICE和DEVICE_EVENT_REMOVE_DEVICE事件。

    /**
     * Called when a device is newly added or a new device is detected or
     * existing device is updated.
     *
     * @param info device info of a new device.
     */
    @ServiceThreadOnly
    final void addCecDevice(HdmiDeviceInfo info) {
        assertRunOnServiceThread();
        Slog.d(TAG, "addCecDevice " + info);
        HdmiDeviceInfo old = addDeviceInfo(info);
        if (info.getLogicalAddress() == mAddress) {
            // The addition of TV device itself should not be notified.
            return;
        }
        if (old == null) {
            invokeDeviceEventListener(info, HdmiControlManager.DEVICE_EVENT_ADD_DEVICE);
        } else if (!old.equals(info)) {
            invokeDeviceEventListener(old, HdmiControlManager.DEVICE_EVENT_REMOVE_DEVICE);
            invokeDeviceEventListener(info, HdmiControlManager.DEVICE_EVENT_ADD_DEVICE);
        }
    }

3.TvInputHardwareManager

和hotplug一样,都是在TvInputManagerService创建的TvInputHardwareManager里面初始化时创建的监听。

    public void onBootPhase(int phase) {
        if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
            IHdmiControlService hdmiControlService = IHdmiControlService.Stub.asInterface(
                    ServiceManager.getService(Context.HDMI_CONTROL_SERVICE));
            if (hdmiControlService != null) {
                try {
                    hdmiControlService.addHotplugEventListener(mHdmiHotplugEventListener);
                    hdmiControlService.addDeviceEventListener(mHdmiDeviceEventListener);

以add为例,首先会将这个HdmiDeviceInfo添加到保存好的列表里面,并发送 ListenerHandler.HDMI_DEVICE_ADDED继续处理。

    private final class HdmiDeviceEventListener extends IHdmiDeviceEventListener.Stub {
        @Override
        public void onStatusChanged(HdmiDeviceInfo deviceInfo, int status) {
            Slog.w(TAG, "onStatusChanged " + deviceInfo + " status " + status);
            if (!deviceInfo.isSourceType()) return;
            synchronized (mLock) {
                int messageType = 0;
                Object obj = null;
                switch (status) {
                    case HdmiControlManager.DEVICE_EVENT_ADD_DEVICE: {
                        if (findHdmiDeviceInfo(deviceInfo.getId()) == null) {
                            mHdmiDeviceList.add(deviceInfo);
                        } else {
                            Slog.w(TAG, "The list already contains " + deviceInfo + "; ignoring.");
                            return;
                        }
                        messageType = ListenerHandler.HDMI_DEVICE_ADDED;
                        obj = deviceInfo;
                        break;
                    }
                    case HdmiControlManager.DEVICE_EVENT_REMOVE_DEVICE: {
                        HdmiDeviceInfo originalDeviceInfo = findHdmiDeviceInfo(deviceInfo.getId());
                        if (!mHdmiDeviceList.remove(originalDeviceInfo)) {
                            Slog.w(TAG, "The list doesn't contain " + deviceInfo + "; ignoring.");
                            return;
                        }
                        messageType = ListenerHandler.HDMI_DEVICE_REMOVED;
                        obj = deviceInfo;
                        break;
                    }
                    case HdmiControlManager.DEVICE_EVENT_UPDATE_DEVICE: {
                        HdmiDeviceInfo originalDeviceInfo = findHdmiDeviceInfo(deviceInfo.getId());
                        if (!mHdmiDeviceList.remove(originalDeviceInfo)) {
                            Slog.w(TAG, "The list doesn't contain " + deviceInfo + "; ignoring.");
                            return;
                        }
                        mHdmiDeviceList.add(deviceInfo);
                        messageType = ListenerHandler.HDMI_DEVICE_UPDATED;
                        obj = deviceInfo;
                        break;
                    }
                }

                Message msg = mHandler.obtainMessage(messageType, 0, 0, obj);
                if (findHardwareInfoForHdmiPortLocked(deviceInfo.getPortId()) != null) {
                    msg.sendToTarget();
                } else {
                    mPendingHdmiDeviceEvents.add(msg);
                }
            }
        }

和hotplug调用InputManagerService的 onStateChanged方法一样,这里会调用onHdmiDeviceAdded方法。需要注意的一点是,实际上add和remove这两个接口的调用相当频繁,在每一次HdmiDeviceInfo发生变更时基本上就会触发一次add和remove,比如原来没拿到vendorId现在拿到了,就更新下。所以这并不能对应实际上的热插拔。在这里进行热插拔的处理是不合适的。

    private class ListenerHandler e
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值