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<ResolveInfo> services = pm.queryIntentServicesAsUser(
new Intent(TvInputService.SERVICE_INTERFACE),
PackageManager.GET_SERVICES | PackageManager.GET_META_DATA,
userId);
...
//每一個TvInputService對應一個TvInputInfo,保存TvInput device信息
List<TvInputInfo> 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<String, TvInputState> inputMap = new HashMap<>();
// A set of all TV input packages.
private final Set<String> packageSet = new HashSet<>();
// A list of all TV content rating systems defined.
private final List<TvContentRatingSystemInfo>
contentRatingSystemList = new ArrayList<>();
// A mapping from the token of a client to its state.
private final Map<IBinder, ClientState> clientStateMap = new HashMap<>();
// A mapping from the name of a TV input service to its state.
private final Map<ComponentName, ServiceState> serviceStateMap = new HashMap<>();
// A mapping from the token of a TV input session to its state.
private final Map<IBinder, SessionState> sessionStateMap = new HashMap<>();
// A set of callbacks.
private final Set<ITvInputManagerCallback> 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<IBinder> sessionTokens = new ArrayList<>();
private final ServiceConnection connection;
private final ComponentName component;
private final boolean isHardware;
private final List<TvInputInfo> 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的流程。
---------------------
作者:zhudaozhuan
來源:CSDN
原文:https://blog.csdn.net/zhudaozhuan/article/details/50849542
版權聲明:本文爲博主原創文章,轉載請附上博文鏈接!