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 ==