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的流程。




更多相关文章

  1. android 通过设置intent-filter 启动程序
  2. 转:adb shell start中启动activity和service
  3. [Android(安卓)Webkit]JNI基础及Java层与C++层的交互
  4. receiver定制自动启动一个程序
  5. volume 服务
  6. Activity四种启动模式及应用
  7. Android(安卓)Studio adb无法启动解决方案
  8. Android(安卓)LayoutInflater原理分析,深入理解View(一)
  9. 【Android】Back Home键监听

随机推荐

  1. android tabwidget 调整高度文字居中
  2. OpenGLES 2.0 在 NDK-r15b上的编译问题
  3. thread in android ndk
  4. Android(安卓)Studio 【Error running ap
  5. android背景图片更换――经典例子
  6. android TextView 跟随 seekBar 一起滑动
  7. EventBus的简单用法及介绍
  8. Android(安卓)Application 和Webview 之
  9. windowIsTranslucent和windowBackground
  10. eclipse开发环境下,如何根据已有代码创建