Android TV Input Framework(TIF)--2 构建TV input list
2016-01-25 20:39
746 查看
TvInputManagerService管理着系统的各种输入,TV Input主要分为三种类型:
hardware input:主要包含TV内建的各种输入端口,比如tuner、component, composite, hdmi。
非hardware input: 视频点播等非内建的硬件端口属于这种类型。
HDMI logic input:带有HDMI CEC的设备属于这种类型。
TvInputManagerService由SystemServer创建,我们先看看它的构造方法
在构造方法中会创建一下TvInputHardwareManager实例,并传入一个HardwareListener实例给TvInputHardwareManager。TvInputHardwareManager通过TvInputHal来获取TV硬件输入的各种状态,并通过HardwareListener通知TvInputManagerService。
TvInputHardwareManager实现了TvInputHal.Callback接口,在构造方法中调用mHal.init()对TvInputHal进行初始化,在TvInputHal初始化过程中,所有TV内建的Input都会通过onDeviceAvailable通知给TvInputHardWareManager,我们看一下onDeviceAvailable的实现:
onDeviceAvailable会调用buildHardwareListLocked把Tv Input的信息放入一个链表,TV Input的信息用TvInputHardwareInfo类表示,
然后通过mHandler.obtainMessage(ListenerHandler.HARDWARE_DEVICE_ADDED, 0, 0, info).sendToTarget()发送到handler线程处理,
还记得TvInputManagerService在创建TvInputHardwareManager的时候传入的HardwareListener吗?它就是mListener, HardwareListener的onHardwareDeviceAdded会被调用,
到目前为止,我们只是对TvInputManagerService的构造方法进行分析,userState.serviceStateMap还是空的,所以这个时候onHardwareDeviceAdded被调用其实什么事情都没有做。
我们接着分析TvInputManagerService的初始化过程,
当第三方的app可以启动的时候,即phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START,调用buildTvInputListLocked开始构建Tv Input List。
这个方法比较长,关键行标上了序号,下面逐一解释:
查找所有的package中的service,如果package的service在AndroidManifest.xml中声明了如下属性:
那么就认为这个service代表一种Tv Input,这些service都继承自TvInputService。对于TV内建的输入端口,还要在package的AndroidManifest.xml声明
对于内建的硬件输入端口,TvInputManangerService会创建对应的ServiceState实例,并跟对应的Service建立连接,
注意this.connection = new InputServiceConnection(component, userId),稍后会用到。
3.在updateServiceConnectionLocked中通过Intent跟service建立连接,这个时候inputList是空的,buildTvInputListLocked继续执行返回。当跟service连接成功以后,serviceState.connection.onServiceConnected会被回调,就是前面说的InputServiceConnection.onServiceConnected。
接着会向Service注册callback,后面会用到。然后通过mTvInputHardwareManager.getHardwareList获取之前初始化的时候保存的Hardware list,调用service的notifyHardwareAdded方法,我们看一下TvInputService的notifyHardwareAdded实现:
通知Handler线程DO_ADD_HARDWARE_TV_INPUT,
然后service的onHardwareAdded方法被调用,并返回TvInputInfo,这代表一个TV Input,然后通过broadcastAddHardwareTvInput通知TvInputManagerService,
我们在跟service建立连接以后,注册了callback,callback的addHardwareTvInput被调用,我们看一下TvInputManagerService中addHardwareTvInput的实现,
addHardwareTvInput会调用addTvInputLocked,addTvInputLocked把TvInputInfo存入serviceState.inputList,接着调用buildTvInputListLocked重新构建Tv input list。
4.再次调用buildTvInputListLocked的时候,serviceState不为null,把serviceState.inputList放入到inputList。
5. 如果不是TV内建的硬件Input,直接创建TvInputInfo并放入InputList。
6. 每一个Tv Input都对应一个TvInputState,通过inputId在inputMap中索引。
7. 如果新构建的inputMap中的inputId在userState.inputMap中没有,表明这个TV input是新增加的,如果TV app有注册callback,那么TV app的onInputAdded会被调用。
8. 如果userState.inputMap中的inputId在新构建的inputMap中没有,表明这个TV Input被移除,如果TV app有注册callback,那么TV app的onInputRemoved会被调用。
9. userState.inputMap被新构建的inputMap替换,至此TV input list构建完成。
下面用序列图来展示一下整个过程
Created with Raphaël 2.1.0TvInputManagerServiceTvInputManagerServiceTvInputHardwareManagerTvInputHardwareManagerTvInputHalTvInputHalTvInputServiceTvInputServiceinitdeviceAvailableFromNativeonDeviceAvaliablebuildHardwareListLockedonHardwareDeviceAddedbuildTvInputListLockedupdateServiceConnectionLockedmContext.bindServiceAsUseronServiceConnectedregisterCallbackgetHardwareListnotifyHardwareAddedonHardwareAddedbroadcastAddHardwareTvInputaddHardwareTvInputaddTvInputLockedbuildTvInputListLockednotifyHdmiDeviceAddedonHdmiDeviceAddedbroadcastAddHdmiTvInputaddHdmiTvInputaddTvInputLockedbuildTvInputListLocked
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 == null) { state = new TvInputState(); } state.info = info; inputMap.put(info.getId(), state); } for (String inputId : inputMap.keySet()) { if (!userState.inputMap.containsKey(inputId)) { ---<7> notifyInputAddedLocked(userState, inputId); } else if (updatedPackages != null) { // Notify the package updates ComponentName component = inputMap.get(inputId).info.getComponent(); for (String updatedPackage : updatedPackages) { if (component.getPackageName().equals(updatedPackage)) { updateServiceConnectionLocked(component, userId); notifyInputUpdatedLocked(userState, inputId); break; } } } } for (String inputId : userState.inputMap.keySet()) { if (!inputMap.containsKey(inputId)) { ---<8> TvInputInfo info = userState.inputMap.get(inputId).info; ServiceState serviceState = userState.serviceStateMap.get(info.getComponent()); if (serviceState != null) { abortPendingCreateSessionRequestsLocked(serviceState, inputId, userId); } notifyInputRemovedLocked(userState, inputId); } } userState.inputMap.clear(); userState.inputMap = inputMap; ---<9> }
这个方法比较长,关键行标上了序号,下面逐一解释:
查找所有的package中的service,如果package的service在AndroidManifest.xml中声明了如下属性:
android:permission="android.permission.BIND_TV_INPUT"
那么就认为这个service代表一种Tv Input,这些service都继承自TvInputService。对于TV内建的输入端口,还要在package的AndroidManifest.xml声明
<uses-permission android:name="android.permission.TV_INPUT_HARDWARE" />
对于内建的硬件输入端口,TvInputManangerService会创建对应的ServiceState实例,并跟对应的Service建立连接,
private ServiceState(ComponentName component, int userId) { this.component = component; this.connection = new InputServiceConnection(component, userId); this.isHardware = hasHardwarePermission(mContext.getPackageManager(), component); }
注意this.connection = new InputServiceConnection(component, userId),稍后会用到。
private void updateServiceConnectionLocked(ComponentName component, int userId) { ... Intent i = new Intent(TvInputService.SERVICE_INTERFACE).setComponent(component); serviceState.bound = mContext.bindServiceAsUser( i, serviceState.connection, Context.BIND_AUTO_CREATE, new UserHandle(userId)); ... }
3.在updateServiceConnectionLocked中通过Intent跟service建立连接,这个时候inputList是空的,buildTvInputListLocked继续执行返回。当跟service连接成功以后,serviceState.connection.onServiceConnected会被回调,就是前面说的InputServiceConnection.onServiceConnected。
public void onServiceConnected(ComponentName component, IBinder service) { ... // Register a callback, if we need to. if (serviceState.isHardware && serviceState.callback == null) { serviceState.callback = new ServiceCallback(mComponent, mUserId); try { serviceState.service.registerCallback(serviceState.callback); } catch (RemoteException e) { Slog.e(TAG, "error in registerCallback", e); } } ... if (serviceState.isHardware) { List<TvInputHardwareInfo> hardwareInfoList = mTvInputHardwareManager.getHardwareList(); for (TvInputHardwareInfo hardwareInfo : hardwareInfoList) { try { serviceState.service.notifyHardwareAdded(hardwareInfo); } catch (RemoteException e) { Slog.e(TAG, "error in notifyHardwareAdded", e); } } List<HdmiDeviceInfo> deviceInfoList = mTvInputHardwareManager.getHdmiDeviceList(); for (HdmiDeviceInfo deviceInfo : deviceInfoList) { try { serviceState.service.notifyHdmiDeviceAdded(deviceInfo); } catch (RemoteException e) { Slog.e(TAG, "error in notifyHdmiDeviceAdded", e); } } } } }
接着会向Service注册callback,后面会用到。然后通过mTvInputHardwareManager.getHardwareList获取之前初始化的时候保存的Hardware list,调用service的notifyHardwareAdded方法,我们看一下TvInputService的notifyHardwareAdded实现:
public void notifyHardwareAdded(TvInputHardwareInfo hardwareInfo) { mServiceHandler.obtainMessage(ServiceHandler.DO_ADD_HARDWARE_TV_INPUT, hardwareInfo).sendToTarget(); }
通知Handler线程DO_ADD_HARDWARE_TV_INPUT,
public final void handleMessage(Message msg) { switch (msg.what) { ... case DO_ADD_HARDWARE_TV_INPUT: { TvInputHardwareInfo hardwareInfo = (TvInputHardwareInfo) msg.obj; TvInputInfo inputInfo = onHardwareAdded(hardwareInfo); if (inputInfo != null) { broadcastAddHardwareTvInput(hardwareInfo.getDeviceId(), inputInfo); } return; } ...
然后service的onHardwareAdded方法被调用,并返回TvInputInfo,这代表一个TV Input,然后通过broadcastAddHardwareTvInput通知TvInputManagerService,
private void broadcastAddHardwareTvInput(int deviceId, TvInputInfo inputInfo) { int n = mCallbacks.beginBroadcast(); for (int i = 0; i < n; ++i) { try { mCallbacks.getBroadcastItem(i).addHardwareTvInput(deviceId, inputInfo); } catch (RemoteException e) { Log.e(TAG, "Error while broadcasting.", e); } } mCallbacks.finishBroadcast(); }
我们在跟service建立连接以后,注册了callback,callback的addHardwareTvInput被调用,我们看一下TvInputManagerService中addHardwareTvInput的实现,
private void addTvInputLocked(TvInputInfo inputInfo) { ServiceState serviceState = getServiceStateLocked(mComponent, mUserId); serviceState.inputList.add(inputInfo); buildTvInputListLocked(mUserId, null); } @Override public void addHardwareTvInput(int deviceId, TvInputInfo inputInfo) { ensureHardwarePermission(); ensureValidInput(inputInfo); synchronized (mLock) { mTvInputHardwareManager.addHardwareTvInput(deviceId, inputInfo); addTvInputLocked(inputInfo); } }
addHardwareTvInput会调用addTvInputLocked,addTvInputLocked把TvInputInfo存入serviceState.inputList,接着调用buildTvInputListLocked重新构建Tv input list。
4.再次调用buildTvInputListLocked的时候,serviceState不为null,把serviceState.inputList放入到inputList。
5. 如果不是TV内建的硬件Input,直接创建TvInputInfo并放入InputList。
6. 每一个Tv Input都对应一个TvInputState,通过inputId在inputMap中索引。
7. 如果新构建的inputMap中的inputId在userState.inputMap中没有,表明这个TV input是新增加的,如果TV app有注册callback,那么TV app的onInputAdded会被调用。
8. 如果userState.inputMap中的inputId在新构建的inputMap中没有,表明这个TV Input被移除,如果TV app有注册callback,那么TV app的onInputRemoved会被调用。
9. userState.inputMap被新构建的inputMap替换,至此TV input list构建完成。
下面用序列图来展示一下整个过程
Created with Raphaël 2.1.0TvInputManagerServiceTvInputManagerServiceTvInputHardwareManagerTvInputHardwareManagerTvInputHalTvInputHalTvInputServiceTvInputServiceinitdeviceAvailableFromNativeonDeviceAvaliablebuildHardwareListLockedonHardwareDeviceAddedbuildTvInputListLockedupdateServiceConnectionLockedmContext.bindServiceAsUseronServiceConnectedregisterCallbackgetHardwareListnotifyHardwareAddedonHardwareAddedbroadcastAddHardwareTvInputaddHardwareTvInputaddTvInputLockedbuildTvInputListLockednotifyHdmiDeviceAddedonHdmiDeviceAddedbroadcastAddHdmiTvInputaddHdmiTvInputaddTvInputLockedbuildTvInputListLocked
相关文章推荐
- Android的文本和输入---拼写检查器
- android单元测试
- Android中pendingIntent的深入理解
- android L 关机流程分析
- ImageView 相关
- Android之WebRTC实现
- Android使用学习之画图(Canvas,Paint)与手势感应及其应用(乒乓球小游戏)
- Android基础知识(1)
- Android TV Input Framework(TIF)--3 显示Tv Input内容
- Android之WebRTC介绍(二)
- Android Settings.System的使用
- Android开发随笔
- Android源码之Matrix
- Android Framework层Power键关机流程
- Android Branch and master source code merge(patch)
- 这些年正Android - 序言
- 这些年正Android - 序言
- Understanding Android Security(安卓安全的理解)
- Understanding Android Security(安卓安全的理解)
- Understanding Android Security(安卓安全的理解)