Use pid and uid for getCurrentTvChannelInfo

so the app tag and app type can be correctly returned,
and add javaDoc.

Bug: 163350497
Test: mmm
Change-Id: Ib2fdddab5e8177edf379d9fbf182a3115cc47bc9
This commit is contained in:
shubang
2020-09-29 23:45:58 -07:00
parent f579dd52ca
commit 6f10e974c8
3 changed files with 120 additions and 32 deletions

View File

@@ -22,19 +22,44 @@ import android.annotation.Nullable;
import android.net.Uri;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
import android.util.Log;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Objects;
/**
* This class is used to specify information of a TV channel.
* @hide
*/
public final class TvChannelInfo implements Parcelable {
static final String TAG = "TvChannelInfo";
/**
* App tag for {@link #getAppTag()}: the corresponding application of the channel is the same as
* the caller.
* <p>{@link #getAppType()} returns {@link #APP_TYPE_SELF} if and only if the app tag is
* {@link #APP_TAG_SELF}.
*/
public static final int APP_TAG_SELF = 0;
/**
* App tag for {@link #getAppType()}: the corresponding application of the channel is the same
* as the caller.
* <p>{@link #getAppType()} returns {@link #APP_TYPE_SELF} if and only if the app tag is
* {@link #APP_TAG_SELF}.
*/
public static final int APP_TYPE_SELF = 1;
/**
* App tag for {@link #getAppType()}: the corresponding app of the channel is a system
* application.
*/
public static final int APP_TYPE_SYSTEM = 2;
/**
* App tag for {@link #getAppType()}: the corresponding app of the channel is not a system
* application.
*/
public static final int APP_TYPE_NON_SYSTEM = 3;
/** @hide */
@@ -68,6 +93,7 @@ public final class TvChannelInfo implements Parcelable {
@AppType private final int mAppType;
private final int mAppTag;
/** @hide */
public TvChannelInfo(
String inputId, @Nullable Uri channelUri, boolean isRecordingSession,
boolean isForeground, @AppType int appType, int appTag) {
@@ -90,24 +116,41 @@ public final class TvChannelInfo implements Parcelable {
mAppTag = source.readInt();
}
/**
* Returns the TV input ID of the channel.
*/
@NonNull
public String getInputId() {
return mInputId;
}
/**
* Returns the channel URI of the channel.
* <p>Returns {@code null} if it's a passthrough input or the permission is not granted.
*/
@Nullable
public Uri getChannelUri() {
return mChannelUri;
}
/**
* Returns {@code true} if the channel session is a recording session.
* @see TvInputService.RecordingSession
*/
public boolean isRecordingSession() {
return mIsRecordingSession;
}
/**
* Returns {@code true} if the application is a foreground application.
* @see android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND
*/
public boolean isForeground() {
return mIsForeground;
}
/**
* Gets app tag.
* Returns the app tag.
* <p>App tag is used to differentiate one app from another.
* {@link #APP_TAG_SELF} is for current app.
*/
@@ -115,6 +158,9 @@ public final class TvChannelInfo implements Parcelable {
return mAppTag;
}
/**
* Returns the app type.
*/
@AppType
public int getAppType() {
return mAppType;
@@ -126,7 +172,7 @@ public final class TvChannelInfo implements Parcelable {
}
@Override
public void writeToParcel(Parcel dest, int flags) {
public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeString(mInputId);
String uriString = mChannelUri == null ? null : mChannelUri.toString();
dest.writeString(uriString);
@@ -145,4 +191,26 @@ public final class TvChannelInfo implements Parcelable {
+ ";appType=" + mAppType
+ ";appTag=" + mAppTag;
}
@Override
public boolean equals(Object o) {
if (!(o instanceof TvChannelInfo)) {
return false;
}
TvChannelInfo other = (TvChannelInfo) o;
return TextUtils.equals(mInputId, other.getInputId())
&& Objects.equals(mChannelUri, other.mChannelUri)
&& mIsRecordingSession == other.mIsRecordingSession
&& mIsForeground == other.mIsForeground
&& mAppType == other.mAppType
&& mAppTag == other.mAppTag;
}
@Override
public int hashCode() {
return Objects.hash(
mInputId, mChannelUri, mIsRecordingSession, mIsForeground, mAppType, mAppTag);
}
}

View File

@@ -900,8 +900,13 @@ public final class TvInputManager {
public void onTvInputInfoUpdated(TvInputInfo inputInfo) {
}
/** @hide */
public void onCurrentTvChannelInfosUpdated(List<TvChannelInfo> tvChannelInfos) {
/**
* This is called when the information about current TV channels has been updated.
*
* @param tvChannelInfos a list of {@link TvChannelInfo} objects of new current channels.
* @hide
*/
public void onCurrentTvChannelInfosUpdated(@NonNull List<TvChannelInfo> tvChannelInfos) {
}
}
@@ -1976,8 +1981,15 @@ public final class TvInputManager {
}
/**
* Returns the list of TV channel information for {@link TvInputService.Session} that are
* currently in use.
* <p> Permission com.android.providers.tv.permission.ACCESS_WATCHED_PROGRAMS is required to get
* the channel URIs. If the permission is not granted, {@link TvChannelInfo#getChannelUri()}
* returns {@code null}.
* @hide
*/
@RequiresPermission("com.android.providers.tv.permission.ACCESS_WATCHED_PROGRAMS")
@NonNull
public List<TvChannelInfo> getCurrentTvChannelInfos() {
try {
return mService.getCurrentTvChannelInfos(mUserId);

View File

@@ -77,6 +77,7 @@ import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.UserHandle;
import android.text.TextUtils;
import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
import android.view.InputChannel;
@@ -709,8 +710,7 @@ public final class TvInputManagerService extends SystemService {
}
sessionState.isCurrent = false;
sessionState.currentChannel = null;
notifyCurrentChannelInfosUpdatedLocked(
userState, getCurrentTvChannelInfosInternalLocked(userState));
notifyCurrentChannelInfosUpdatedLocked(userState);
} catch (RemoteException | SessionNotFoundException e) {
Slog.e(TAG, "error in releaseSession", e);
} finally {
@@ -851,15 +851,18 @@ public final class TvInputManagerService extends SystemService {
}
}
private void notifyCurrentChannelInfosUpdatedLocked(
UserState userState, List<TvChannelInfo> infos) {
private void notifyCurrentChannelInfosUpdatedLocked(UserState userState) {
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);
ITvInputManagerCallback callback = userState.mCallbacks.getBroadcastItem(i);
Pair<Integer, Integer> pidUid = userState.callbackPidUidMap.get(callback);
List<TvChannelInfo> infos = getCurrentTvChannelInfosInternalLocked(
userState, pidUid.first, pidUid.second);
callback.onCurrentTvChannelInfosUpdated(infos);
} catch (RemoteException e) {
Slog.e(TAG, "failed to report updated current channel infos to callback", e);
}
@@ -1063,14 +1066,19 @@ public final class TvInputManagerService extends SystemService {
@Override
public void registerCallback(final ITvInputManagerCallback callback, int userId) {
final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(),
Binder.getCallingUid(), userId, "registerCallback");
int callingPid = Binder.getCallingPid();
int callingUid = Binder.getCallingUid();
final int resolvedUserId = resolveCallingUserId(callingPid, callingUid, userId,
"registerCallback");
final long identity = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
final UserState userState = getOrCreateUserStateLocked(resolvedUserId);
if (!userState.mCallbacks.register(callback)) {
Slog.e(TAG, "client process has already died");
} else {
userState.callbackPidUidMap.put(
callback, Pair.create(callingPid, callingUid));
}
}
} finally {
@@ -1087,6 +1095,7 @@ public final class TvInputManagerService extends SystemService {
synchronized (mLock) {
UserState userState = getOrCreateUserStateLocked(resolvedUserId);
userState.mCallbacks.unregister(callback);
userState.callbackPidUidMap.remove(callback);
}
} finally {
Binder.restoreCallingIdentity(identity);
@@ -1419,8 +1428,8 @@ public final class TvInputManagerService extends SystemService {
@Override
public void tune(IBinder sessionToken, final Uri channelUri, Bundle params, int userId) {
final int callingUid = Binder.getCallingUid();
final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
userId, "tune");
final int callingPid = Binder.getCallingPid();
final int resolvedUserId = resolveCallingUserId(callingPid, callingUid, userId, "tune");
final long identity = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
@@ -1432,8 +1441,7 @@ public final class TvInputManagerService extends SystemService {
if (sessionState != null) {
sessionState.isCurrent = true;
sessionState.currentChannel = channelUri;
notifyCurrentChannelInfosUpdatedLocked(
userState, getCurrentTvChannelInfosInternalLocked(userState));
notifyCurrentChannelInfosUpdatedLocked(userState);
}
if (TvContract.isChannelUriForPassthroughInput(channelUri)) {
// Do not log the watch history for passthrough inputs.
@@ -2090,16 +2098,13 @@ public final class TvInputManagerService extends SystemService {
@Override
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);
return getCurrentTvChannelInfosInternalLocked(userState);
}
} finally {
Binder.restoreCallingIdentity(identity);
int callingPid = Binder.getCallingPid();
int callingUid = Binder.getCallingUid();
final int resolvedUserId = resolveCallingUserId(callingPid, callingUid, userId,
"getTvCurrentChannelInfos");
synchronized (mLock) {
UserState userState = getOrCreateUserStateLocked(resolvedUserId);
return getCurrentTvChannelInfosInternalLocked(userState, callingPid, callingUid);
}
}
@@ -2273,14 +2278,15 @@ public final class TvInputManagerService extends SystemService {
}
}
private List<TvChannelInfo> getCurrentTvChannelInfosInternalLocked(UserState userState) {
private List<TvChannelInfo> getCurrentTvChannelInfosInternalLocked(
UserState userState, int callingPid, int callingUid) {
List<TvChannelInfo> channelInfos = new ArrayList<>();
boolean watchedProgramsAccess = hasAccessWatchedProgramsPermission();
boolean watchedProgramsAccess = hasAccessWatchedProgramsPermission(callingPid, callingUid);
for (SessionState state : userState.sessionStateMap.values()) {
if (state.isCurrent) {
Integer appTag;
int appType;
if (state.callingUid == Binder.getCallingUid()) {
if (state.callingUid == callingUid) {
appTag = APP_TAG_SELF;
appType = TvChannelInfo.APP_TYPE_SELF;
} else {
@@ -2322,8 +2328,8 @@ public final class TvInputManagerService extends SystemService {
return false;
}
private boolean hasAccessWatchedProgramsPermission() {
return mContext.checkCallingPermission(PERMISSION_ACCESS_WATCHED_PROGRAMS)
private boolean hasAccessWatchedProgramsPermission(int callingPid, int callingUid) {
return mContext.checkPermission(PERMISSION_ACCESS_WATCHED_PROGRAMS, callingPid, callingUid)
== PackageManager.PERMISSION_GRANTED;
}
@@ -2360,6 +2366,9 @@ public final class TvInputManagerService extends SystemService {
private final RemoteCallbackList<ITvInputManagerCallback> mCallbacks =
new RemoteCallbackList<ITvInputManagerCallback>();
private final Map<ITvInputManagerCallback, Pair<Integer, Integer>> callbackPidUidMap =
new HashMap<>();
// The token of a "main" TV input session.
private IBinder mainSessionToken = null;
@@ -2712,8 +2721,7 @@ public final class TvInputManagerService extends SystemService {
mSessionState.isCurrent = true;
mSessionState.currentChannel = channelUri;
UserState userState = getOrCreateUserStateLocked(mSessionState.userId);
notifyCurrentChannelInfosUpdatedLocked(
userState, getCurrentTvChannelInfosInternalLocked(userState));
notifyCurrentChannelInfosUpdatedLocked(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