TIF: handle a race condition when a session is crashed

Currently, TIMS has a logic for handling session crash (binderDied).
However, this can be racy if the client calls an operation right before it gets
ITvInputClient.onSessionReleased() callback. This change handles those request
gracefully without causing a crash in the client side.

Bug: 18612616
Change-Id: I37241e05d53f3cca693e0239fc9ad5dce02fc925
This commit is contained in:
Dongwon Kang
2014-12-04 18:08:00 +09:00
parent 130e30fe24
commit fdce9e541e

View File

@@ -461,7 +461,7 @@ public final class TvInputManagerService extends SystemService {
UserState userState = getUserStateLocked(userId);
SessionState sessionState = userState.sessionStateMap.get(sessionToken);
if (sessionState == null) {
throw new IllegalArgumentException("Session state not found for token " + sessionToken);
throw new SessionNotFoundException("Session state not found for token " + sessionToken);
}
// Only the application that requested this session or the system can access it.
if (callingUid != Process.SYSTEM_UID && callingUid != sessionState.callingUid) {
@@ -589,18 +589,22 @@ public final class TvInputManagerService extends SystemService {
}
private void releaseSessionLocked(IBinder sessionToken, int callingUid, int userId) {
SessionState sessionState = getSessionStateLocked(sessionToken, callingUid, userId);
if (sessionState.session != null) {
UserState userState = getUserStateLocked(userId);
if (sessionToken == userState.mainSessionToken) {
setMainLocked(sessionToken, false, callingUid, userId);
}
try {
SessionState sessionState = null;
try {
sessionState = getSessionStateLocked(sessionToken, callingUid, userId);
if (sessionState.session != null) {
UserState userState = getUserStateLocked(userId);
if (sessionToken == userState.mainSessionToken) {
setMainLocked(sessionToken, false, callingUid, userId);
}
sessionState.session.release();
} catch (RemoteException e) {
Slog.e(TAG, "session process has already died", e);
}
sessionState.session = null;
} catch (RemoteException | SessionNotFoundException e) {
Slog.e(TAG, "error in releaseSession", e);
} finally {
if (sessionState != null) {
sessionState.session = null;
}
}
removeSessionStateLocked(sessionToken, userId);
}
@@ -648,19 +652,19 @@ public final class TvInputManagerService extends SystemService {
}
private void setMainLocked(IBinder sessionToken, boolean isMain, int callingUid, int userId) {
SessionState sessionState = getSessionStateLocked(sessionToken, callingUid, userId);
if (sessionState.hardwareSessionToken != null) {
sessionState = getSessionStateLocked(sessionState.hardwareSessionToken,
Process.SYSTEM_UID, userId);
}
ServiceState serviceState = getServiceStateLocked(sessionState.info.getComponent(), userId);
if (!serviceState.isHardware) {
return;
}
ITvInputSession session = getSessionLocked(sessionState);
try {
SessionState sessionState = getSessionStateLocked(sessionToken, callingUid, userId);
if (sessionState.hardwareSessionToken != null) {
sessionState = getSessionStateLocked(sessionState.hardwareSessionToken,
Process.SYSTEM_UID, userId);
}
ServiceState serviceState = getServiceStateLocked(sessionState.info.getComponent(), userId);
if (!serviceState.isHardware) {
return;
}
ITvInputSession session = getSessionLocked(sessionState);
session.setMain(isMain);
} catch (RemoteException e) {
} catch (RemoteException | SessionNotFoundException e) {
Slog.e(TAG, "error in setMain", e);
}
}
@@ -1085,7 +1089,7 @@ public final class TvInputManagerService extends SystemService {
getSessionLocked(sessionState.hardwareSessionToken,
Process.SYSTEM_UID, resolvedUserId).setSurface(surface);
}
} catch (RemoteException e) {
} catch (RemoteException | SessionNotFoundException e) {
Slog.e(TAG, "error in setSurface", e);
}
}
@@ -1116,7 +1120,7 @@ public final class TvInputManagerService extends SystemService {
getSessionLocked(sessionState.hardwareSessionToken, Process.SYSTEM_UID,
resolvedUserId).dispatchSurfaceChanged(format, width, height);
}
} catch (RemoteException e) {
} catch (RemoteException | SessionNotFoundException e) {
Slog.e(TAG, "error in dispatchSurfaceChanged", e);
}
}
@@ -1146,7 +1150,7 @@ public final class TvInputManagerService extends SystemService {
Process.SYSTEM_UID, resolvedUserId).setVolume((volume > 0.0f)
? REMOTE_VOLUME_ON : REMOTE_VOLUME_OFF);
}
} catch (RemoteException e) {
} catch (RemoteException | SessionNotFoundException e) {
Slog.e(TAG, "error in setVolume", e);
}
}
@@ -1183,7 +1187,7 @@ public final class TvInputManagerService extends SystemService {
args.arg5 = sessionToken;
mWatchLogHandler.obtainMessage(WatchLogHandler.MSG_LOG_WATCH_START, args)
.sendToTarget();
} catch (RemoteException e) {
} catch (RemoteException | SessionNotFoundException e) {
Slog.e(TAG, "error in tune", e);
return;
}
@@ -1205,7 +1209,7 @@ public final class TvInputManagerService extends SystemService {
try {
getSessionLocked(sessionToken, callingUid, resolvedUserId)
.requestUnblockContent(unblockedRating);
} catch (RemoteException e) {
} catch (RemoteException | SessionNotFoundException e) {
Slog.e(TAG, "error in requestUnblockContent", e);
}
}
@@ -1225,7 +1229,7 @@ public final class TvInputManagerService extends SystemService {
try {
getSessionLocked(sessionToken, callingUid, resolvedUserId)
.setCaptionEnabled(enabled);
} catch (RemoteException e) {
} catch (RemoteException | SessionNotFoundException e) {
Slog.e(TAG, "error in setCaptionEnabled", e);
}
}
@@ -1245,7 +1249,7 @@ public final class TvInputManagerService extends SystemService {
try {
getSessionLocked(sessionToken, callingUid, resolvedUserId).selectTrack(
type, trackId);
} catch (RemoteException e) {
} catch (RemoteException | SessionNotFoundException e) {
Slog.e(TAG, "error in selectTrack", e);
}
}
@@ -1266,7 +1270,7 @@ public final class TvInputManagerService extends SystemService {
try {
getSessionLocked(sessionToken, callingUid, resolvedUserId)
.appPrivateCommand(command, data);
} catch (RemoteException e) {
} catch (RemoteException | SessionNotFoundException e) {
Slog.e(TAG, "error in appPrivateCommand", e);
}
}
@@ -1287,7 +1291,7 @@ public final class TvInputManagerService extends SystemService {
try {
getSessionLocked(sessionToken, callingUid, resolvedUserId)
.createOverlayView(windowToken, frame);
} catch (RemoteException e) {
} catch (RemoteException | SessionNotFoundException e) {
Slog.e(TAG, "error in createOverlayView", e);
}
}
@@ -1307,7 +1311,7 @@ public final class TvInputManagerService extends SystemService {
try {
getSessionLocked(sessionToken, callingUid, resolvedUserId)
.relayoutOverlayView(frame);
} catch (RemoteException e) {
} catch (RemoteException | SessionNotFoundException e) {
Slog.e(TAG, "error in relayoutOverlayView", e);
}
}
@@ -1327,7 +1331,7 @@ public final class TvInputManagerService extends SystemService {
try {
getSessionLocked(sessionToken, callingUid, resolvedUserId)
.removeOverlayView();
} catch (RemoteException e) {
} catch (RemoteException | SessionNotFoundException e) {
Slog.e(TAG, "error in removeOverlayView", e);
}
}
@@ -2340,4 +2344,13 @@ public final class TvInputManagerService extends SystemService {
}
}
}
private static class SessionNotFoundException extends IllegalArgumentException {
public SessionNotFoundException() {
}
public SessionNotFoundException(String name) {
super(name);
}
}
}