android TIF啓動流程--轉載

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 
版權聲明:本文爲博主原創文章,轉載請附上博文鏈接!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章