From fdce9e541e143332ba4ece6a0bda4f11520f0b07 Mon Sep 17 00:00:00 2001 From: Dongwon Kang Date: Thu, 4 Dec 2014 18:08:00 +0900 Subject: [PATCH] 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 --- .../server/tv/TvInputManagerService.java | 79 +++++++++++-------- 1 file changed, 46 insertions(+), 33 deletions(-) diff --git a/services/core/java/com/android/server/tv/TvInputManagerService.java b/services/core/java/com/android/server/tv/TvInputManagerService.java index 5ab3fa1e84864..5375bfcf3bd72 100644 --- a/services/core/java/com/android/server/tv/TvInputManagerService.java +++ b/services/core/java/com/android/server/tv/TvInputManagerService.java @@ -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); + } + } }