TIF是Tv Input Framework的简称,是Android在5.0后加入的tv框架,为了支持android tv功能。
public TvInputManagerService(Context context) {
super(context);
mContext = context;
mWatchLogHandler = new WatchLogHandler(mContext.getContentResolver(),
IoThread.get().getLooper());
mTvInputHardwareManager = new TvInputHardwareManager(context, new HardwareListener());
synchronized (mLock) {
getOrCreateUserStateLocked(mCurrentUserId);
}
}
主要实例化TvInputHardwareManager,TvInputHardwareManager辅助TvInputManagerService管理Tv Input device,包含Tv Input Device Status变化等。
@Override
public void onStart() {
publishBinderService(Context.TV_INPUT_SERVICE, new BinderService());
}
将ITvInputManager service注册到ServiceManager,在BinderService类中实现ITvInputManager的aidl接口,这个实现代码很长,也是TvInputManagerService主要业务,java api层的接口实现就是在BinderService。
@Override
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);
}
对于phase的两种事件解释如下:
/**
* After receiving this boot phase, services can safely call into core system services
* such as the PowerManager or PackageManager.
*/
public static final int PHASE_SYSTEM_SERVICES_READY = 500;
/**
* After receiving this boot phase, services can start/bind to third party apps.
* Apps will be able to make Binder calls into services at this point.
*/
public static final int PHASE_THIRD_PARTY_APPS_CAN_START = 600;
private void registerBroadcastReceivers() {
PackageMonitor monitor = new PackageMonitor() {
private void buildTvInputList(String[] packages) {
synchronized (mLock) {
buildTvInputListLocked(getChangingUserId(), packages);
buildTvContentRatingSystemListLocked(getChangingUserId());
}
}
public void onPackageUpdateFinished(String packageName, int uid)
public void onPackagesAvailable(String[] packages)
public void onPackagesUnavailable(String[] packages)
public void onSomePackagesChanged()
public boolean onPackageChanged(String packageName, int uid, String[] components)
public void onPackageRemoved(String packageName, int uid)
static {
sPackageFilt.addAction(Intent.ACTION_PACKAGE_ADDED);
sPackageFilt.addAction(Intent.ACTION_PACKAGE_REMOVED);
sPackageFilt.addAction(Intent.ACTION_PACKAGE_CHANGED);
sPackageFilt.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
sPackageFilt.addAction(Intent.ACTION_PACKAGE_RESTARTED);
sPackageFilt.addDataScheme("package");
sNonDataFilt.addAction(Intent.ACTION_UID_REMOVED);
sNonDataFilt.addAction(Intent.ACTION_USER_STOPPED);
sExternalFilt.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
sExternalFilt.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
}
private void buildTvInputListLocked(int userId, String[] updatedPackages) {
// 获取系统所有的TvInputService,在AndroidManifest.xml中注册TvInputService时需要带关键字TvInputService.SERVICE_INTERFACE
PackageManager pm = mContext.getPackageManager();
List services = pm.queryIntentServicesAsUser(
new Intent(TvInputService.SERVICE_INTERFACE),
PackageManager.GET_SERVICES | PackageManager.GET_META_DATA,
userId);
...
//每一个TvInputService对应一个TvInputInfo,保存TvInput device信息
List inputList = new ArrayList<>();
for (ResolveInfo ri : services) {
ServiceInfo si = ri.serviceInfo;
//每个TvInputService需要注册BIND_TV_INPUT权限,否则无法启动
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);
// 注册TvInputService的app要注册TV_INPUT_HARDWARE权限,否则也无法启动
if (hasHardwarePermission(pm, component)) {
...
serviceState = new ServiceState(component, userId);
userState.serviceStateMap.put(component, serviceState);
//绑定TvInputService
updateServiceConnectionLocked(component, userId);
...
//保存TvInputService对应的TvInputInfo到TvInput List
inputList.addAll(serviceState.inputList);
....
for (String inputId : inputMap.keySet()) {
if (!userState.inputMap.containsKey(inputId)) {
// Tv Input device status变化,通知上层
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)) {
// TvInputService所在的apk有更新,更新service的连接状态
updateServiceConnectionLocked(component, userId);
notifyInputUpdatedLocked(userState, inputId);
break;
}
}
}
}
....
for (String inputId : userState.inputMap.keySet()) {
if (!inputMap.containsKey(inputId)) {
TvInputInfo info = userState.inputMap.get(inputId).info;
ServiceState serviceState = userState.serviceStateMap.get(info.getComponent());
if (serviceState != null) {
abortPendingCreateSessionRequestsLocked(serviceState, inputId, userId);
}
//tv input device有移除,通知上层
notifyInputRemovedLocked(userState, inputId);
}
}
在TIF设计中考虑了Android多用户的情况,不同的用户,可能会安装不同TvInputService组件。因此TvInputService的状态,Tv input device的状态等需要分别去管理。UserState内部类的添加实现了对多用户的支持。
private static final class UserState {
// A mapping from the TV input id to its TvInputState.
private Map inputMap = new HashMap<>();
// A set of all TV input packages.
private final Set packageSet = new HashSet<>();
// A list of all TV content rating systems defined.
private final List
contentRatingSystemList = new ArrayList<>();
// A mapping from the token of a client to its state.
private final Map clientStateMap = new HashMap<>();
// A mapping from the name of a TV input service to its state.
private final Map serviceStateMap = new HashMap<>();
// A mapping from the token of a TV input session to its state.
private final Map sessionStateMap = new HashMap<>();
// A set of callbacks.
private final Set callbackSet = new HashSet<>();
// The token of a "main" TV input session.
private IBinder mainSessionToken = null;
// Persistent data store for all internal settings maintained by the TV input manager
// service.
private final PersistentDataStore persistentDataStore;
private UserState(Context context, int userId) {
persistentDataStore = new PersistentDataStore(context, userId);
}
}
ServiceState是对TvInputService状态的记录,TvInputState是对TvInputDevice状态的记录,packageset是对所有TvInputService组件的记录。
private final class ServiceState {
private final List sessionTokens = new ArrayList<>();
private final ServiceConnection connection;
private final ComponentName component;
private final boolean isHardware;
private final List inputList = new ArrayList<>();
private ITvInputService service;
private ServiceCallback callback;
private boolean bound;
private boolean reconnecting;
private ServiceState(ComponentName component, int userId) {
this.component = component;
this.connection = new InputServiceConnection(component, userId);
this.isHardware = hasHardwarePermission(mContext.getPackageManager(), component);
}
}
private static final class TvInputState {
// A TvInputInfo object which represents the TV input.
private TvInputInfo info;
// The state of TV input. Connected by default.
private int state = INPUT_STATE_CONNECTED;
@Override
public String toString() {
return "info: " + info + "; state: " + state;
}
}
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 | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE,
new UserHandle(userId));
bind后,可以拿到TvInputService实例。
private final class InputServiceConnection implements ServiceConnection {
...
@Override
public void onServiceConnected(ComponentName component, IBinder service) {
if (DEBUG) {
Slog.d(TAG, "onServiceConnected(component=" + component + ")");
}
synchronized (mLock) {
UserState userState = getOrCreateUserStateLocked(mUserId);
ServiceState serviceState = userState.serviceStateMap.get(mComponent);
serviceState.service = ITvInputService.Stub.asInterface(service);
在TvInputManagerService中会监控设备插拔事件,并将插拔事件给到TvInputService,TvInputService可以进行对应的逻辑处理。
private final class HardwareListener implements TvInputHardwareManager.Listener {
@Override
public void onStateChanged(String inputId, int state) {
synchronized (mLock) {
setStateLocked(inputId, state, mCurrentUserId);
}
}
@Override
public void onHardwareDeviceAdded(TvInputHardwareInfo info) {
synchronized (mLock) {
UserState userState = getOrCreateUserStateLocked(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);
}
}
}
}
@Override
public void onHardwareDeviceRemoved(TvInputHardwareInfo info) {
synchronized (mLock) {
UserState userState = getOrCreateUserStateLocked(mCurrentUserId);
// Broadcast the event to all hardware inputs.
for (ServiceState serviceState : userState.serviceStateMap.values()) {
if (!serviceState.isHardware || serviceState.service == null) continue;
try {
serviceState.service.notifyHardwareRemoved(info);
} catch (RemoteException e) {
Slog.e(TAG, "error in notifyHardwareRemoved", e);
}
}
}
}
@Override
public void onHdmiDeviceAdded(HdmiDeviceInfo deviceInfo) {
synchronized (mLock) {
UserState userState = getOrCreateUserStateLocked(mCurrentUserId);
// Broadcast the event to all hardware inputs.
for (ServiceState serviceState : userState.serviceStateMap.values()) {
if (!serviceState.isHardware || serviceState.service == null) continue;
try {
serviceState.service.notifyHdmiDeviceAdded(deviceInfo);
} catch (RemoteException e) {
Slog.e(TAG, "error in notifyHdmiDeviceAdded", e);
}
}
}
}
@Override
public void onHdmiDeviceRemoved(HdmiDeviceInfo deviceInfo) {
synchronized (mLock) {
UserState userState = getOrCreateUserStateLocked(mCurrentUserId);
// Broadcast the event to all hardware inputs.
for (ServiceState serviceState : userState.serviceStateMap.values()) {
if (!serviceState.isHardware || serviceState.service == null) continue;
try {
serviceState.service.notifyHdmiDeviceRemoved(deviceInfo);
} catch (RemoteException e) {
Slog.e(TAG, "error in notifyHdmiDeviceRemoved", e);
}
}
}
}
@Override
public void onHdmiDeviceUpdated(String inputId, HdmiDeviceInfo deviceInfo) {
synchronized (mLock) {
Integer state;
switch (deviceInfo.getDevicePowerStatus()) {
case HdmiControlManager.POWER_STATUS_ON:
state = INPUT_STATE_CONNECTED;
break;
case HdmiControlManager.POWER_STATUS_STANDBY:
case HdmiControlManager.POWER_STATUS_TRANSIENT_TO_ON:
case HdmiControlManager.POWER_STATUS_TRANSIENT_TO_STANDBY:
state = INPUT_STATE_CONNECTED_STANDBY;
break;
case HdmiControlManager.POWER_STATUS_UNKNOWN:
default:
state = null;
break;
}
if (state != null) {
setStateLocked(inputId, state, mCurrentUserId);
}
}
}
}
TvInputHardwareManager是辅助TvInputManagerService管理的类。
public TvInputHardwareManager(Context context, Listener listener) {
mContext = context;
mListener = listener;
mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
mHal.init();
}
TvInputHardwareManager的构造函数很简单,实例化AudioManager以及HAL init,变量mHal是TvInputHal。
public void init() {
synchronized (mLock) {
mPtr = nativeOpen(mHandler.getLooper().getQueue());
}
}
初始化函数是打开一个Message Queue。
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);
hdmiControlService.addSystemAudioModeChangeListener(
mHdmiSystemAudioModeChangeListener);
mHdmiDeviceList.addAll(hdmiControlService.getInputDevices());
} catch (RemoteException e) {
Slog.w(TAG, "Error registering listeners to HdmiControlService:", e);
}
} else {
Slog.w(TAG, "HdmiControlService is not available");
}
final IntentFilter filter = new IntentFilter();
filter.addAction(AudioManager.VOLUME_CHANGED_ACTION);
filter.addAction(AudioManager.STREAM_MUTE_CHANGED_ACTION);
mContext.registerReceiver(mVolumeReceiver, filter);
updateVolume();
}
}
主要是对HDMI Control service实例化以及初始化,并注册音量变化广播。
public interface Callback {
void onDeviceAvailable(TvInputHardwareInfo info, TvStreamConfig[] configs);
void onDeviceUnavailable(int deviceId);
void onStreamConfigurationChanged(int deviceId, TvStreamConfig[] configs);
void onFirstFrameCaptured(int deviceId, int streamId);
}
即TvInputHardwareManager对device状态的监听,是由TvInputHal通知出来。
// Called from native
private void deviceAvailableFromNative(TvInputHardwareInfo info) {
if (DEBUG) {
Slog.d(TAG, "deviceAvailableFromNative: info = " + info);
}
mHandler.obtainMessage(EVENT_DEVICE_AVAILABLE, info).sendToTarget();
}
private void deviceUnavailableFromNative(int deviceId) {
mHandler.obtainMessage(EVENT_DEVICE_UNAVAILABLE, deviceId, 0).sendToTarget();
}
private void streamConfigsChangedFromNative(int deviceId) {
mHandler.obtainMessage(EVENT_STREAM_CONFIGURATION_CHANGED, deviceId, 0).sendToTarget();
}
private void firstFrameCapturedFromNative(int deviceId, int streamId) {
mHandler.sendMessage(
mHandler.obtainMessage(EVENT_STREAM_CONFIGURATION_CHANGED, deviceId, streamId));
}
JNI层call到TvInputHal java层接口,将Event给到TvInputHal层,TvInputHal发送Handler消息,在HandlerMessage函数处理handler消息:
@Override
public boolean handleMessage(Message msg) {
switch (msg.what) {
case EVENT_DEVICE_AVAILABLE: {
TvStreamConfig[] configs;
TvInputHardwareInfo info = (TvInputHardwareInfo)msg.obj;
synchronized (mLock) {
retrieveStreamConfigsLocked(info.getDeviceId());
if (DEBUG) {
Slog.d(TAG, "EVENT_DEVICE_AVAILABLE: info = " + info);
}
configs = mStreamConfigs.get(info.getDeviceId());
}
mCallback.onDeviceAvailable(info, configs);
break;
}
case EVENT_DEVICE_UNAVAILABLE: {
int deviceId = msg.arg1;
if (DEBUG) {
Slog.d(TAG, "EVENT_DEVICE_UNAVAILABLE: deviceId = " + deviceId);
}
mCallback.onDeviceUnavailable(deviceId);
break;
}
case EVENT_STREAM_CONFIGURATION_CHANGED: {
TvStreamConfig[] configs;
int deviceId = msg.arg1;
synchronized (mLock) {
if (DEBUG) {
Slog.d(TAG, "EVENT_STREAM_CONFIGURATION_CHANGED: deviceId = " + deviceId);
}
retrieveStreamConfigsLocked(deviceId);
configs = mStreamConfigs.get(deviceId);
}
mCallback.onStreamConfigurationChanged(deviceId, configs);
break;
}
case EVENT_FIRST_FRAME_CAPTURED: {
int deviceId = msg.arg1;
int streamId = msg.arg2;
mCallback.onFirstFrameCaptured(deviceId, streamId);
break;
}
default:
Slog.e(TAG, "Unknown event: " + msg);
return false;
}
return true;
}
处理Handler消息即通过callback将Message给到TvInputHardwareManager。