Loading media/java/android/media/tv/ITvInputManager.aidl +1 −1 Original line number Diff line number Diff line Loading @@ -89,7 +89,7 @@ interface ITvInputManager { void timeShiftSetPlaybackParams(in IBinder sessionToken, in PlaybackParams params, int userId); void timeShiftEnablePositionTracking(in IBinder sessionToken, boolean enable, int userId); List<TvChannelInfo> getTvCurrentChannelInfos(int userId); List<TvChannelInfo> getCurrentTvChannelInfos(int userId); // For the recording session void startRecording(in IBinder sessionToken, in Uri programUri, in Bundle params, int userId); Loading media/java/android/media/tv/ITvInputManagerCallback.aidl +2 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package android.media.tv; import android.media.tv.TvChannelInfo; import android.media.tv.TvInputInfo; /** Loading @@ -28,4 +29,5 @@ oneway interface ITvInputManagerCallback { void onInputUpdated(in String inputId); void onInputStateChanged(in String inputId, int state); void onTvInputInfoUpdated(in TvInputInfo TvInputInfo); void onCurrentTvChannelInfosUpdated(in List<TvChannelInfo> currentTvChannelInfos); } media/java/android/media/tv/TvInputManager.java +25 −4 Original line number Diff line number Diff line Loading @@ -899,6 +899,10 @@ public final class TvInputManager { */ public void onTvInputInfoUpdated(TvInputInfo inputInfo) { } /** @hide */ public void onCurrentTvChannelInfosUpdated(List<TvChannelInfo> tvChannelInfos) { } } private static final class TvInputCallbackRecord { Loading Loading @@ -958,6 +962,16 @@ public final class TvInputManager { } }); } public void postCurrentTvChannelInfosUpdated( final List<TvChannelInfo> currentTvChannelInfos) { mHandler.post(new Runnable() { @Override public void run() { mCallback.onCurrentTvChannelInfosUpdated(currentTvChannelInfos); } }); } } /** Loading Loading @@ -1262,6 +1276,15 @@ public final class TvInputManager { } } } @Override public void onCurrentTvChannelInfosUpdated(List<TvChannelInfo> currentTvChannelInfos) { synchronized (mLock) { for (TvInputCallbackRecord record : mCallbackRecords) { record.postCurrentTvChannelInfosUpdated(currentTvChannelInfos); } } } }; try { if (mService != null) { Loading Loading @@ -1955,11 +1978,9 @@ public final class TvInputManager { /** * @hide */ public List<TvChannelInfo> getTvCurrentChannelInfos() { // TODO: handle retuned() cases and add a method to TvInputCallback // TODO: unhide public List<TvChannelInfo> getCurrentTvChannelInfos() { try { return mService.getTvCurrentChannelInfos(mUserId); return mService.getCurrentTvChannelInfos(mUserId); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } Loading services/core/java/com/android/server/tv/TvInputManagerService.java +91 −62 Original line number Diff line number Diff line Loading @@ -699,8 +699,8 @@ public final class TvInputManagerService extends SystemService { SessionState sessionState = null; try { sessionState = getSessionStateLocked(sessionToken, callingUid, userId); if (sessionState.session != null) { UserState userState = getOrCreateUserStateLocked(userId); if (sessionState.session != null) { if (sessionToken == userState.mainSessionToken) { setMainLocked(sessionToken, false, callingUid, userId); } Loading @@ -709,6 +709,8 @@ public final class TvInputManagerService extends SystemService { } sessionState.isCurrent = false; sessionState.currentChannel = null; notifyCurrentChannelInfosUpdatedLocked( userState, getCurrentTvChannelInfosInternalLocked(userState)); } catch (RemoteException | SessionNotFoundException e) { Slog.e(TAG, "error in releaseSession", e); } finally { Loading Loading @@ -849,6 +851,22 @@ public final class TvInputManagerService extends SystemService { } } private void notifyCurrentChannelInfosUpdatedLocked( UserState userState, List<TvChannelInfo> infos) { if (DEBUG) { Slog.d(TAG, "notifyCurrentChannelInfosUpdatedLocked"); } int n = userState.mCallbacks.beginBroadcast(); for (int i = 0; i < n; ++i) { try { userState.mCallbacks.getBroadcastItem(i).onCurrentTvChannelInfosUpdated(infos); } catch (RemoteException e) { Slog.e(TAG, "failed to report updated current channel infos to callback", e); } } userState.mCallbacks.finishBroadcast(); } private void updateTvInputInfoLocked(UserState userState, TvInputInfo inputInfo) { if (DEBUG) { Slog.d(TAG, "updateTvInputInfoLocked(inputInfo=" + inputInfo + ")"); Loading Loading @@ -1414,6 +1432,8 @@ public final class TvInputManagerService extends SystemService { if (sessionState != null) { sessionState.isCurrent = true; sessionState.currentChannel = channelUri; notifyCurrentChannelInfosUpdatedLocked( userState, getCurrentTvChannelInfosInternalLocked(userState)); } if (TvContract.isChannelUriForPassthroughInput(channelUri)) { // Do not log the watch history for passthrough inputs. Loading Loading @@ -2069,79 +2089,20 @@ public final class TvInputManagerService extends SystemService { } @Override public List<TvChannelInfo> getTvCurrentChannelInfos(@UserIdInt int userId) { public List<TvChannelInfo> getCurrentTvChannelInfos(@UserIdInt int userId) { final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), Binder.getCallingUid(), userId, "getTvCurrentChannelInfos"); final long identity = Binder.clearCallingIdentity(); try { synchronized (mLock) { UserState userState = getOrCreateUserStateLocked(resolvedUserId); List<TvChannelInfo> channelInfos = new ArrayList<>(); boolean watchedProgramsAccess = hasAccessWatchedProgramsPermission(); for (SessionState state : userState.sessionStateMap.values()) { if (state.isCurrent) { Integer appTag; int appType; if (state.callingUid == Binder.getCallingUid()) { appTag = APP_TAG_SELF; appType = TvChannelInfo.APP_TYPE_SELF; } else { appTag = userState.mAppTagMap.get(state.callingUid); if (appTag == null) { appTag = userState.mNextAppTag++; userState.mAppTagMap.put(state.callingUid, appTag); } appType = isSystemApp(state.componentName.getPackageName()) ? TvChannelInfo.APP_TYPE_SYSTEM : TvChannelInfo.APP_TYPE_NON_SYSTEM; } channelInfos.add(new TvChannelInfo( state.inputId, watchedProgramsAccess ? state.currentChannel : null, state.isRecordingSession, isForeground(state.callingPid), appType, appTag)); } } return channelInfos; return getCurrentTvChannelInfosInternalLocked(userState); } } finally { Binder.restoreCallingIdentity(identity); } } protected boolean isForeground(int pid) { if (mActivityManager == null) { return false; } List<RunningAppProcessInfo> appProcesses = mActivityManager.getRunningAppProcesses(); if (appProcesses == null) { return false; } for (RunningAppProcessInfo appProcess : appProcesses) { if (appProcess.pid == pid && appProcess.importance == RunningAppProcessInfo.IMPORTANCE_FOREGROUND) { return true; } } return false; } private boolean hasAccessWatchedProgramsPermission() { return mContext.checkCallingPermission(PERMISSION_ACCESS_WATCHED_PROGRAMS) == PackageManager.PERMISSION_GRANTED; } private boolean isSystemApp(String pkg) { try { return (mContext.getPackageManager().getApplicationInfo(pkg, 0).flags & ApplicationInfo.FLAG_SYSTEM) != 0; } catch (NameNotFoundException e) { return false; } } /** * Add a hardware device in the TvInputHardwareManager for CTS testing * purpose. Loading Loading @@ -2312,6 +2273,69 @@ public final class TvInputManagerService extends SystemService { } } private List<TvChannelInfo> getCurrentTvChannelInfosInternalLocked(UserState userState) { List<TvChannelInfo> channelInfos = new ArrayList<>(); boolean watchedProgramsAccess = hasAccessWatchedProgramsPermission(); for (SessionState state : userState.sessionStateMap.values()) { if (state.isCurrent) { Integer appTag; int appType; if (state.callingUid == Binder.getCallingUid()) { appTag = APP_TAG_SELF; appType = TvChannelInfo.APP_TYPE_SELF; } else { appTag = userState.mAppTagMap.get(state.callingUid); if (appTag == null) { appTag = userState.mNextAppTag++; userState.mAppTagMap.put(state.callingUid, appTag); } appType = isSystemApp(state.componentName.getPackageName()) ? TvChannelInfo.APP_TYPE_SYSTEM : TvChannelInfo.APP_TYPE_NON_SYSTEM; } channelInfos.add(new TvChannelInfo( state.inputId, watchedProgramsAccess ? state.currentChannel : null, state.isRecordingSession, isForeground(state.callingPid), appType, appTag)); } } return channelInfos; } private boolean isForeground(int pid) { if (mActivityManager == null) { return false; } List<RunningAppProcessInfo> appProcesses = mActivityManager.getRunningAppProcesses(); if (appProcesses == null) { return false; } for (RunningAppProcessInfo appProcess : appProcesses) { if (appProcess.pid == pid && appProcess.importance == RunningAppProcessInfo.IMPORTANCE_FOREGROUND) { return true; } } return false; } private boolean hasAccessWatchedProgramsPermission() { return mContext.checkCallingPermission(PERMISSION_ACCESS_WATCHED_PROGRAMS) == PackageManager.PERMISSION_GRANTED; } private boolean isSystemApp(String pkg) { try { return (mContext.getPackageManager().getApplicationInfo(pkg, 0).flags & ApplicationInfo.FLAG_SYSTEM) != 0; } catch (NameNotFoundException e) { return false; } } private static final class UserState { // A mapping from the TV input id to its TvInputState. private Map<String, TvInputState> inputMap = new HashMap<>(); Loading Loading @@ -2685,6 +2709,11 @@ public final class TvInputManagerService extends SystemService { if (mSessionState.session == null || mSessionState.client == null) { return; } mSessionState.isCurrent = true; mSessionState.currentChannel = channelUri; UserState userState = getOrCreateUserStateLocked(mSessionState.userId); notifyCurrentChannelInfosUpdatedLocked( userState, getCurrentTvChannelInfosInternalLocked(userState)); try { // TODO: Consider adding this channel change in the watch log. When we do // that, how we can protect the watch log from malicious tv inputs should Loading Loading
media/java/android/media/tv/ITvInputManager.aidl +1 −1 Original line number Diff line number Diff line Loading @@ -89,7 +89,7 @@ interface ITvInputManager { void timeShiftSetPlaybackParams(in IBinder sessionToken, in PlaybackParams params, int userId); void timeShiftEnablePositionTracking(in IBinder sessionToken, boolean enable, int userId); List<TvChannelInfo> getTvCurrentChannelInfos(int userId); List<TvChannelInfo> getCurrentTvChannelInfos(int userId); // For the recording session void startRecording(in IBinder sessionToken, in Uri programUri, in Bundle params, int userId); Loading
media/java/android/media/tv/ITvInputManagerCallback.aidl +2 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package android.media.tv; import android.media.tv.TvChannelInfo; import android.media.tv.TvInputInfo; /** Loading @@ -28,4 +29,5 @@ oneway interface ITvInputManagerCallback { void onInputUpdated(in String inputId); void onInputStateChanged(in String inputId, int state); void onTvInputInfoUpdated(in TvInputInfo TvInputInfo); void onCurrentTvChannelInfosUpdated(in List<TvChannelInfo> currentTvChannelInfos); }
media/java/android/media/tv/TvInputManager.java +25 −4 Original line number Diff line number Diff line Loading @@ -899,6 +899,10 @@ public final class TvInputManager { */ public void onTvInputInfoUpdated(TvInputInfo inputInfo) { } /** @hide */ public void onCurrentTvChannelInfosUpdated(List<TvChannelInfo> tvChannelInfos) { } } private static final class TvInputCallbackRecord { Loading Loading @@ -958,6 +962,16 @@ public final class TvInputManager { } }); } public void postCurrentTvChannelInfosUpdated( final List<TvChannelInfo> currentTvChannelInfos) { mHandler.post(new Runnable() { @Override public void run() { mCallback.onCurrentTvChannelInfosUpdated(currentTvChannelInfos); } }); } } /** Loading Loading @@ -1262,6 +1276,15 @@ public final class TvInputManager { } } } @Override public void onCurrentTvChannelInfosUpdated(List<TvChannelInfo> currentTvChannelInfos) { synchronized (mLock) { for (TvInputCallbackRecord record : mCallbackRecords) { record.postCurrentTvChannelInfosUpdated(currentTvChannelInfos); } } } }; try { if (mService != null) { Loading Loading @@ -1955,11 +1978,9 @@ public final class TvInputManager { /** * @hide */ public List<TvChannelInfo> getTvCurrentChannelInfos() { // TODO: handle retuned() cases and add a method to TvInputCallback // TODO: unhide public List<TvChannelInfo> getCurrentTvChannelInfos() { try { return mService.getTvCurrentChannelInfos(mUserId); return mService.getCurrentTvChannelInfos(mUserId); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } Loading
services/core/java/com/android/server/tv/TvInputManagerService.java +91 −62 Original line number Diff line number Diff line Loading @@ -699,8 +699,8 @@ public final class TvInputManagerService extends SystemService { SessionState sessionState = null; try { sessionState = getSessionStateLocked(sessionToken, callingUid, userId); if (sessionState.session != null) { UserState userState = getOrCreateUserStateLocked(userId); if (sessionState.session != null) { if (sessionToken == userState.mainSessionToken) { setMainLocked(sessionToken, false, callingUid, userId); } Loading @@ -709,6 +709,8 @@ public final class TvInputManagerService extends SystemService { } sessionState.isCurrent = false; sessionState.currentChannel = null; notifyCurrentChannelInfosUpdatedLocked( userState, getCurrentTvChannelInfosInternalLocked(userState)); } catch (RemoteException | SessionNotFoundException e) { Slog.e(TAG, "error in releaseSession", e); } finally { Loading Loading @@ -849,6 +851,22 @@ public final class TvInputManagerService extends SystemService { } } private void notifyCurrentChannelInfosUpdatedLocked( UserState userState, List<TvChannelInfo> infos) { if (DEBUG) { Slog.d(TAG, "notifyCurrentChannelInfosUpdatedLocked"); } int n = userState.mCallbacks.beginBroadcast(); for (int i = 0; i < n; ++i) { try { userState.mCallbacks.getBroadcastItem(i).onCurrentTvChannelInfosUpdated(infos); } catch (RemoteException e) { Slog.e(TAG, "failed to report updated current channel infos to callback", e); } } userState.mCallbacks.finishBroadcast(); } private void updateTvInputInfoLocked(UserState userState, TvInputInfo inputInfo) { if (DEBUG) { Slog.d(TAG, "updateTvInputInfoLocked(inputInfo=" + inputInfo + ")"); Loading Loading @@ -1414,6 +1432,8 @@ public final class TvInputManagerService extends SystemService { if (sessionState != null) { sessionState.isCurrent = true; sessionState.currentChannel = channelUri; notifyCurrentChannelInfosUpdatedLocked( userState, getCurrentTvChannelInfosInternalLocked(userState)); } if (TvContract.isChannelUriForPassthroughInput(channelUri)) { // Do not log the watch history for passthrough inputs. Loading Loading @@ -2069,79 +2089,20 @@ public final class TvInputManagerService extends SystemService { } @Override public List<TvChannelInfo> getTvCurrentChannelInfos(@UserIdInt int userId) { public List<TvChannelInfo> getCurrentTvChannelInfos(@UserIdInt int userId) { final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), Binder.getCallingUid(), userId, "getTvCurrentChannelInfos"); final long identity = Binder.clearCallingIdentity(); try { synchronized (mLock) { UserState userState = getOrCreateUserStateLocked(resolvedUserId); List<TvChannelInfo> channelInfos = new ArrayList<>(); boolean watchedProgramsAccess = hasAccessWatchedProgramsPermission(); for (SessionState state : userState.sessionStateMap.values()) { if (state.isCurrent) { Integer appTag; int appType; if (state.callingUid == Binder.getCallingUid()) { appTag = APP_TAG_SELF; appType = TvChannelInfo.APP_TYPE_SELF; } else { appTag = userState.mAppTagMap.get(state.callingUid); if (appTag == null) { appTag = userState.mNextAppTag++; userState.mAppTagMap.put(state.callingUid, appTag); } appType = isSystemApp(state.componentName.getPackageName()) ? TvChannelInfo.APP_TYPE_SYSTEM : TvChannelInfo.APP_TYPE_NON_SYSTEM; } channelInfos.add(new TvChannelInfo( state.inputId, watchedProgramsAccess ? state.currentChannel : null, state.isRecordingSession, isForeground(state.callingPid), appType, appTag)); } } return channelInfos; return getCurrentTvChannelInfosInternalLocked(userState); } } finally { Binder.restoreCallingIdentity(identity); } } protected boolean isForeground(int pid) { if (mActivityManager == null) { return false; } List<RunningAppProcessInfo> appProcesses = mActivityManager.getRunningAppProcesses(); if (appProcesses == null) { return false; } for (RunningAppProcessInfo appProcess : appProcesses) { if (appProcess.pid == pid && appProcess.importance == RunningAppProcessInfo.IMPORTANCE_FOREGROUND) { return true; } } return false; } private boolean hasAccessWatchedProgramsPermission() { return mContext.checkCallingPermission(PERMISSION_ACCESS_WATCHED_PROGRAMS) == PackageManager.PERMISSION_GRANTED; } private boolean isSystemApp(String pkg) { try { return (mContext.getPackageManager().getApplicationInfo(pkg, 0).flags & ApplicationInfo.FLAG_SYSTEM) != 0; } catch (NameNotFoundException e) { return false; } } /** * Add a hardware device in the TvInputHardwareManager for CTS testing * purpose. Loading Loading @@ -2312,6 +2273,69 @@ public final class TvInputManagerService extends SystemService { } } private List<TvChannelInfo> getCurrentTvChannelInfosInternalLocked(UserState userState) { List<TvChannelInfo> channelInfos = new ArrayList<>(); boolean watchedProgramsAccess = hasAccessWatchedProgramsPermission(); for (SessionState state : userState.sessionStateMap.values()) { if (state.isCurrent) { Integer appTag; int appType; if (state.callingUid == Binder.getCallingUid()) { appTag = APP_TAG_SELF; appType = TvChannelInfo.APP_TYPE_SELF; } else { appTag = userState.mAppTagMap.get(state.callingUid); if (appTag == null) { appTag = userState.mNextAppTag++; userState.mAppTagMap.put(state.callingUid, appTag); } appType = isSystemApp(state.componentName.getPackageName()) ? TvChannelInfo.APP_TYPE_SYSTEM : TvChannelInfo.APP_TYPE_NON_SYSTEM; } channelInfos.add(new TvChannelInfo( state.inputId, watchedProgramsAccess ? state.currentChannel : null, state.isRecordingSession, isForeground(state.callingPid), appType, appTag)); } } return channelInfos; } private boolean isForeground(int pid) { if (mActivityManager == null) { return false; } List<RunningAppProcessInfo> appProcesses = mActivityManager.getRunningAppProcesses(); if (appProcesses == null) { return false; } for (RunningAppProcessInfo appProcess : appProcesses) { if (appProcess.pid == pid && appProcess.importance == RunningAppProcessInfo.IMPORTANCE_FOREGROUND) { return true; } } return false; } private boolean hasAccessWatchedProgramsPermission() { return mContext.checkCallingPermission(PERMISSION_ACCESS_WATCHED_PROGRAMS) == PackageManager.PERMISSION_GRANTED; } private boolean isSystemApp(String pkg) { try { return (mContext.getPackageManager().getApplicationInfo(pkg, 0).flags & ApplicationInfo.FLAG_SYSTEM) != 0; } catch (NameNotFoundException e) { return false; } } private static final class UserState { // A mapping from the TV input id to its TvInputState. private Map<String, TvInputState> inputMap = new HashMap<>(); Loading Loading @@ -2685,6 +2709,11 @@ public final class TvInputManagerService extends SystemService { if (mSessionState.session == null || mSessionState.client == null) { return; } mSessionState.isCurrent = true; mSessionState.currentChannel = channelUri; UserState userState = getOrCreateUserStateLocked(mSessionState.userId); notifyCurrentChannelInfosUpdatedLocked( userState, getCurrentTvChannelInfosInternalLocked(userState)); try { // TODO: Consider adding this channel change in the watch log. When we do // that, how we can protect the watch log from malicious tv inputs should Loading