Android TV Input Framework(TIF)--2 构建TV input list

本文详细解析了Android TV Input Framework的构建过程,包括TvInputManagerService如何管理TV输入,如硬件输入、非硬件输入和HDMI逻辑输入。在TvInputHal的初始化中,TV内建输入设备通过onDeviceAvailable传递给TvInputHardwareManager。TvInputManagerService在构建Tv Input List时,检查AndroidManifest.xml中的服务声明,与服务建立连接,并在连接成功后调用回调方法,最终构建完整的TV input list。
摘要由CSDN通过智能技术生成

TvInputManagerService管理着系统的各种输入,TV Input主要分为三种类型:

  • hardware input:主要包含TV内建的各种输入端口,比如tuner、component, composite, hdmi。

  • 非hardware input: 视频点播等非内建的硬件端口属于这种类型。

  • HDMI logic input:带有HDMI CEC的设备属于这种类型。


TvInputManagerService由SystemServer创建,我们先看看它的构造方法

  public TvInputManagerService(Context context) {
        super(context);
        ...
        mTvInputHardwareManager = new TvInputHardwareManager(context, new HardwareListener());

        synchronized (mLock) {
            mUserStates.put(mCurrentUserId, new UserState(mContext, mCurrentUserId));
        }
    }

在构造方法中会创建一下TvInputHardwareManager实例,并传入一个HardwareListener实例给TvInputHardwareManager。TvInputHardwareManager通过TvInputHal来获取TV硬件输入的各种状态,并通过HardwareListener通知TvInputManagerService。

class TvInputHardwareManager implements TvInputHal.Callback

public interface Callback {
        public void onDeviceAvailable(
                TvInputHardwareInfo info, TvStreamConfig[] configs);
        public void onDeviceUnavailable(int deviceId);
        public void onStreamConfigurationChanged(int deviceId, TvStreamConfig[] configs);
        public void onFirstFrameCaptured(int deviceId, int streamId);
    }

 public TvInputHardwareManager(Context context, Listener listener) {
        mContext = context;
        mListener = listener;
        ...
        mHal.init();
    }

TvInputHardwareManager实现了TvInputHal.Callback接口,在构造方法中调用mHal.init()对TvInputHal进行初始化,在TvInputHal初始化过程中,所有TV内建的Input都会通过onDeviceAvailable通知给TvInputHardWareManager,我们看一下onDeviceAvailable的实现:

  public void onDeviceAvailable(TvInputHardwareInfo info, TvStreamConfig[] configs) {
        synchronized (mLock) {
            ...
            buildHardwareListLocked();
            mHandler.obtainMessage(
                    ListenerHandler.HARDWARE_DEVICE_ADDED, 0, 0, info).sendToTarget();
            ...
            }
        }
    }

onDeviceAvailable会调用buildHardwareListLocked把Tv Input的信息放入一个链表,TV Input的信息用TvInputHardwareInfo类表示,

private void buildHardwareListLocked() {
        mHardwareList.clear();
        for (int i = 0; i < mConnections.size(); ++i) {
            mHardwareList.add(mConnections.valueAt(i).getHardwareInfoLocked());
        }
    }

然后通过mHandler.obtainMessage(ListenerHandler.HARDWARE_DEVICE_ADDED, 0, 0, info).sendToTarget()发送到handler线程处理,

 public final void handleMessage(Message msg) {
            switch (msg.what) {
                ...
                case HARDWARE_DEVICE_ADDED: {
                    TvInputHardwareInfo info = (TvInputHardwareInfo) msg.obj;
                    mListener.onHardwareDeviceAdded(info);
                    break;
                }
                ...

还记得TvInputManagerService在创建TvInputHardwareManager的时候传入的HardwareListener吗?它就是mListener, HardwareListener的onHardwareDeviceAdded会被调用,

public void onHardwareDeviceAdded(TvInputHardwareInfo info) {
            synchronized (mLock) {
                UserState userState = getUserStateLocked(mCurrentUserId);
                // Broadcast the event to all hardware inputs.
                for (ServiceState serviceState : userState.serviceStateMap.values()) {
                    if (!serviceState.isHardware || serviceState.service == null) continue;
                    try {
                        serviceState.service.notifyHardwareAdded(info);
                    } catch (RemoteException e) {
                        Slog.e(TAG, "error in notifyHardwareAdded", e);
                    }
                }
            }
        }

到目前为止,我们只是对TvInputManagerService的构造方法进行分析,userState.serviceStateMap还是空的,所以这个时候onHardwareDeviceAdded被调用其实什么事情都没有做。


我们接着分析TvInputManagerService的初始化过程,

 public void onBootPhase(int phase) {
        if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
            registerBroadcastReceivers();
        } else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
            synchronized (mLock) {
                buildTvInputListLocked(mCurrentUserId, null);
                buildTvContentRatingSystemListLocked(mCurrentUserId);
            }
        }
        mTvInputHardwareManager.onBootPhase(phase);
    }

当第三方的app可以启动的时候,即phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START,调用buildTvInputListLocked开始构建Tv Input List。

    private void buildTvInputListLocked(int userId, String[] updatedPackages) {
        UserState userState = getUserStateLocked(userId);
        userState.packageSet.clear();

        if (DEBUG) Slog.d(TAG, "buildTvInputList");
        PackageManager pm = mContext.getPackageManager();
        List<ResolveInfo> services = pm.queryIntentServices(
                new Intent(TvInputService.SERVICE_INTERFACE),
                PackageManager.GET_SERVICES | PackageManager.GET_META_DATA);                       ---<1>
        List<TvInputInfo> inputList = new ArrayList<TvInputInfo>();
        for (ResolveInfo ri : services) {
            ServiceInfo si = ri.serviceInfo;
            if (!android.Manifest.permission.BIND_TV_INPUT.equals(si.permission)) {
                Slog.w(TAG, "Skipping TV input " + si.name + ": it does not require the permission "
                        + android.Manifest.permission.BIND_TV_INPUT);
                continue;
            }
            ComponentName component = new ComponentName(si.packageName, si.name);
            if (hasHardwarePermission(pm, component)) {
                ServiceState serviceState = userState.serviceStateMap.get(component);
                if (serviceState == null) {
                    // We see this hardware TV input service for the first time; we need to
                    // prepare the ServiceState object so that we can connect to the service and
                    // let it add TvInputInfo objects to mInputList if there's any.
                    serviceState = new ServiceState(component, userId);                     ---<2>
                    userState.serviceStateMap.put(component, serviceState);
                    updateServiceConnectionLocked(component, userId);    ---<3>
                } else {
                    inputList.addAll(serviceState.inputList);            ---<4>
                }
            } else {
                try {
                    inputList.add(TvInputInfo.createTvInputInfo(mContext, ri));---<5>
                } catch (XmlPullParserException | IOException e) {
                    Slog.e(TAG, "failed to load TV input " + si.name, e);
                    continue;
                }
            }
            userState.packageSet.add(si.packageName);
        }

        Map<String, TvInputState> inputMap = new HashMap<String, TvInputState>();             ---<6>
        for (TvInputInfo info : inputList) {
            if (DEBUG) {
                Slog.d(TAG, "add " + info.getId());
            }
            TvInputState state = userState.inputMap.get(info.getId());
            if (state == 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值