android TIF启动流程
16lz
2021-01-26
TIF是Tv Input Framework的简称,是Android在5.0后加入的tv框架,为了支持android tv功能。
1 TvInputManagerService启动流程
TvInputManagerService在TIF框架结构中扮演Java service层的角色,向java api提供接口实现。在SystemServer的Main Thread里面,执行run函数时,回去启动各种services : startBootstrapServices();
startCoreServices();
startOtherServices();
在startOtherServices()函数里会去启动TvInputManagerService服务: if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_LIVE_TV)) {
mSystemServiceManager.startService(TvInputManagerService.class);
} 支持TIF,平台需要配置feature PackageManager.FEATURE_LIVE_TV,否则无法启动TvInputManagerService. startService函数会做下面几件事情:
1)TvInputManagerService注册到SystemService // Register it.
mServices.add(service);
2)通过反射获取TvInputManagerService实例
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变化等。 WatchLogHandler是一个Handler,用于处理watch事件,对于这个handler的解释如下:
// There are only two kinds of watch events that can happen on the system:
// 1. The current TV input session is tuned to a new channel.
// 2. The session is released for some reason.
看实现是有一个db去保存watch 状态,可以控制start watch或end watch. Handler使用的Looper不是System Server Main thread Looper,所以不会卡System Server Main Thread.
3)调用TvInputManagerService onStart函数
@Override public void onStart() { publishBinderService(Context.TV_INPUT_SERVICE, new BinderService()); }
将ITvInputManager service注册到ServiceManager,在BinderService类中实现ITvInputManager的aidl接口,这个实现代码很长,也是TvInputManagerService主要业务,java api层的接口实现就是在BinderService。 4)调用TvInputManagerService onBootPhase函数
在TvInputManagerService启动时,会call到如下函数:
@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;
看起来是TvInputManagerService在启动时,有两个启动完毕时间点,一个是可以被core service call,另外一种是被third party apps start/bind 在收到PHASE_SYSTEM_SERVICES_READY event后,会去注册广播接收器: private void registerBroadcastReceivers() {PackageMonitor monitor = new PackageMonitor() {
这里有一个内部类PackageMonitor,有很多的call back接口,以及内部接口: private void buildTvInputList(String[] packages) { synchronized (mLock) { buildTvInputListLocked(getChangingUserId(), packages); buildTvContentRatingSystemListLocked(getChangingUserId()); } }
call back接口主要为: 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)
看起来都是对package事件的处理,那么看下PackageMonitor注册广播类型: 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); }
看起来都是和apps相关的,这里的apps应该是指TvInputService的实现。 在TIF中,每一种通道可以理解为一个Tv Input Device,有一个Tv Input Service去实现相关的业务逻辑。 比如对于Tunel device,有切台,修改音量,创建会话等行为,都需要Tv Input Service去实现。 当Tv Input Service的apps卸载或安装时,会触发这里的广播reciver. 在收到PHASE_THIRD_PARTY_APPS_CAN_START事件时,会去call buildTvInputListLocked函数, buildTvInputListLocked函数实现如下: 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; } }
2 TvInputService启动
启动TvInputService的方法是通过bind方式: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管理的类。 3 TvInputHardwareManager介绍
在TvInputManagerSerivce的构造函数中会实例化TvInputHardwareManager:mTvInputHardwareManager = new TvInputHardwareManager(context, new HardwareListener());
参数HardwareListener即是TvInputManagerService监控Hardware的监听器。
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。 TvInputHal的类继承关系:
final class TvInputHal implements Handler.Callback {
主要功能是处理队列消息。
public void init() { synchronized (mLock) { mPtr = nativeOpen(mHandler.getLooper().getQueue()); } }
初始化函数是打开一个Message Queue。 在TvInputManagerService中启动时会call到onBootPhase函数:
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实例化以及初始化,并注册音量变化广播。 TvInputHardwareManager类的实现:
class TvInputHardwareManager implements TvInputHal.Callback
TvInputHal主要是对Message队列消息的处理,Callback函数定义如下:
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通知出来。 TvInputHal.java
// 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。 Tv Input Device state变化的流程可以汇总如下:
HAL->JNI->TvInputHal->TvInputHardwareManager->TvInputManagerService->TvInputService
通过这篇文章,学习了TvInputManagerService启动TvInputService的过程,以及TvInputManagerService,TvInputHardwareManager以及TvinputHal传递TvInputDevice的流程。
更多相关文章
- android 通过设置intent-filter 启动程序
- 转:adb shell start中启动activity和service
- [Android(安卓)Webkit]JNI基础及Java层与C++层的交互
- receiver定制自动启动一个程序
- volume 服务
- Activity四种启动模式及应用
- Android(安卓)Studio adb无法启动解决方案
- Android(安卓)LayoutInflater原理分析,深入理解View(一)
- 【Android】Back Home键监听