Loading services/core/java/com/android/server/tv/TvInputManagerService.java +104 −61 Original line number Diff line number Diff line Loading @@ -415,7 +415,38 @@ public final class TvInputManagerService extends SystemService { if (mCurrentUserId == userId) { return; } clearSessionAndServiceStatesLocked(mUserStates.get(mCurrentUserId)); UserState userState = mUserStates.get(mCurrentUserId); List<SessionState> sessionStatesToRelease = new ArrayList<>(); for (SessionState sessionState : userState.sessionStateMap.values()) { if (sessionState.session != null && !sessionState.isRecordingSession) { sessionStatesToRelease.add(sessionState); } } for (SessionState sessionState : sessionStatesToRelease) { try { sessionState.session.release(); } catch (RemoteException e) { Slog.e(TAG, "error in release", e); } clearSessionAndNotifyClientLocked(sessionState); } for (Iterator<ComponentName> it = userState.serviceStateMap.keySet().iterator(); it.hasNext(); ) { ComponentName component = it.next(); ServiceState serviceState = userState.serviceStateMap.get(component); if (serviceState != null && serviceState.sessionTokens.isEmpty()) { if (serviceState.callback != null) { try { serviceState.service.unregisterCallback(serviceState.callback); } catch (RemoteException e) { Slog.e(TAG, "error in unregisterCallback", e); } } mContext.unbindService(serviceState.connection); it.remove(); } } mCurrentUserId = userId; getOrCreateUserStateLocked(userId); Loading @@ -426,28 +457,36 @@ public final class TvInputManagerService extends SystemService { } } private void clearSessionAndNotifyClientLocked(SessionState state) { if (state.client != null) { try { state.client.onSessionReleased(state.seq); } catch(RemoteException e) { Slog.e(TAG, "error in onSessionReleased", e); } } // If there are any other sessions based on this session, they should be released. UserState userState = getOrCreateUserStateLocked(state.userId); for (SessionState sessionState : userState.sessionStateMap.values()) { if (state.sessionToken == sessionState.hardwareSessionToken) { releaseSessionLocked(sessionState.sessionToken, Process.SYSTEM_UID, state.userId); try { sessionState.client.onSessionReleased(sessionState.seq); } catch (RemoteException e) { Slog.e(TAG, "error in onSessionReleased", e); } } } removeSessionStateLocked(state.sessionToken, state.userId); } private void removeUser(int userId) { synchronized (mLock) { UserState userState = mUserStates.get(userId); if (userState == null) { return; } clearSessionAndServiceStatesLocked(userState); // Clear everything else. userState.inputMap.clear(); userState.packageSet.clear(); userState.contentRatingSystemList.clear(); userState.clientStateMap.clear(); userState.callbackSet.clear(); userState.mainSessionToken = null; mUserStates.remove(userId); } } private void clearSessionAndServiceStatesLocked(UserState userState) { // Release created sessions. // Release all created sessions. for (SessionState state : userState.sessionStateMap.values()) { if (state.session != null) { try { Loading @@ -473,6 +512,17 @@ public final class TvInputManagerService extends SystemService { } } userState.serviceStateMap.clear(); // Clear everything else. userState.inputMap.clear(); userState.packageSet.clear(); userState.contentRatingSystemList.clear(); userState.clientStateMap.clear(); userState.callbackSet.clear(); userState.mainSessionToken = null; mUserStates.remove(userId); } } private ContentResolver getContentResolverForUser(int userId) { Loading Loading @@ -539,11 +589,6 @@ public final class TvInputManagerService extends SystemService { false, methodName, null); } private static boolean shouldMaintainConnection(ServiceState serviceState) { return !serviceState.sessionTokens.isEmpty() || serviceState.isHardware; // TODO: Find a way to maintain connection to hardware TV input service only when necessary. } private void updateServiceConnectionLocked(ComponentName component, int userId) { UserState userState = getOrCreateUserStateLocked(userId); ServiceState serviceState = userState.serviceStateMap.get(component); Loading @@ -557,8 +602,19 @@ public final class TvInputManagerService extends SystemService { } serviceState.reconnecting = false; } boolean maintainConnection = shouldMaintainConnection(serviceState); if (serviceState.service == null && maintainConnection && userId == mCurrentUserId) { boolean shouldBind; if (userId == mCurrentUserId) { shouldBind = !serviceState.sessionTokens.isEmpty() || serviceState.isHardware; } else { // For a non-current user, // if sessionTokens is not empty, it contains recording sessions only // because other sessions must have been removed while switching user // and non-recording sessions are not created by createSession(). shouldBind = !serviceState.sessionTokens.isEmpty(); } if (serviceState.service == null && shouldBind) { // This means that the service is not yet connected but its state indicates that we // have pending requests. Then, connect the service. if (serviceState.bound) { Loading @@ -575,7 +631,7 @@ public final class TvInputManagerService extends SystemService { i, serviceState.connection, Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE, new UserHandle(userId)); } else if (serviceState.service != null && !maintainConnection) { } else if (serviceState.service != null && !shouldBind) { // This means that the service is already connected but its state indicates that we have // nothing to do with it. Then, disconnect the service. if (DEBUG) { Loading Loading @@ -811,7 +867,7 @@ public final class TvInputManagerService extends SystemService { int oldState = inputState.state; inputState.state = state; if (serviceState != null && serviceState.service == null && shouldMaintainConnection(serviceState)) { && (!serviceState.sessionTokens.isEmpty() || serviceState.isHardware)) { // We don't notify state change while reconnecting. It should remain disconnected. return; } Loading Loading @@ -1080,6 +1136,13 @@ public final class TvInputManagerService extends SystemService { final long identity = Binder.clearCallingIdentity(); try { synchronized (mLock) { if (userId != mCurrentUserId && !isRecordingSession) { // A non-recording session of a backgroud (non-current) user // should not be created. // Let the client get onConnectionFailed callback for this case. sendSessionTokenToClientLocked(client, inputId, null, null, seq); return; } UserState userState = getOrCreateUserStateLocked(resolvedUserId); TvInputState inputState = userState.inputMap.get(inputId); if (inputState == null) { Loading Loading @@ -2073,27 +2136,7 @@ public final class TvInputManagerService extends SystemService { public void binderDied() { synchronized (mLock) { session = null; if (client != null) { try { client.onSessionReleased(seq); } catch(RemoteException e) { Slog.e(TAG, "error in onSessionReleased", e); } } // If there are any other sessions based on this session, they should be released. UserState userState = getOrCreateUserStateLocked(userId); for (SessionState sessionState : userState.sessionStateMap.values()) { if (sessionToken == sessionState.hardwareSessionToken) { releaseSessionLocked(sessionState.sessionToken, Process.SYSTEM_UID, userId); try { sessionState.client.onSessionReleased(sessionState.seq); } catch (RemoteException e) { Slog.e(TAG, "error in onSessionReleased", e); } } } removeSessionStateLocked(sessionToken, userId); clearSessionAndNotifyClientLocked(this); } } } Loading Loading
services/core/java/com/android/server/tv/TvInputManagerService.java +104 −61 Original line number Diff line number Diff line Loading @@ -415,7 +415,38 @@ public final class TvInputManagerService extends SystemService { if (mCurrentUserId == userId) { return; } clearSessionAndServiceStatesLocked(mUserStates.get(mCurrentUserId)); UserState userState = mUserStates.get(mCurrentUserId); List<SessionState> sessionStatesToRelease = new ArrayList<>(); for (SessionState sessionState : userState.sessionStateMap.values()) { if (sessionState.session != null && !sessionState.isRecordingSession) { sessionStatesToRelease.add(sessionState); } } for (SessionState sessionState : sessionStatesToRelease) { try { sessionState.session.release(); } catch (RemoteException e) { Slog.e(TAG, "error in release", e); } clearSessionAndNotifyClientLocked(sessionState); } for (Iterator<ComponentName> it = userState.serviceStateMap.keySet().iterator(); it.hasNext(); ) { ComponentName component = it.next(); ServiceState serviceState = userState.serviceStateMap.get(component); if (serviceState != null && serviceState.sessionTokens.isEmpty()) { if (serviceState.callback != null) { try { serviceState.service.unregisterCallback(serviceState.callback); } catch (RemoteException e) { Slog.e(TAG, "error in unregisterCallback", e); } } mContext.unbindService(serviceState.connection); it.remove(); } } mCurrentUserId = userId; getOrCreateUserStateLocked(userId); Loading @@ -426,28 +457,36 @@ public final class TvInputManagerService extends SystemService { } } private void clearSessionAndNotifyClientLocked(SessionState state) { if (state.client != null) { try { state.client.onSessionReleased(state.seq); } catch(RemoteException e) { Slog.e(TAG, "error in onSessionReleased", e); } } // If there are any other sessions based on this session, they should be released. UserState userState = getOrCreateUserStateLocked(state.userId); for (SessionState sessionState : userState.sessionStateMap.values()) { if (state.sessionToken == sessionState.hardwareSessionToken) { releaseSessionLocked(sessionState.sessionToken, Process.SYSTEM_UID, state.userId); try { sessionState.client.onSessionReleased(sessionState.seq); } catch (RemoteException e) { Slog.e(TAG, "error in onSessionReleased", e); } } } removeSessionStateLocked(state.sessionToken, state.userId); } private void removeUser(int userId) { synchronized (mLock) { UserState userState = mUserStates.get(userId); if (userState == null) { return; } clearSessionAndServiceStatesLocked(userState); // Clear everything else. userState.inputMap.clear(); userState.packageSet.clear(); userState.contentRatingSystemList.clear(); userState.clientStateMap.clear(); userState.callbackSet.clear(); userState.mainSessionToken = null; mUserStates.remove(userId); } } private void clearSessionAndServiceStatesLocked(UserState userState) { // Release created sessions. // Release all created sessions. for (SessionState state : userState.sessionStateMap.values()) { if (state.session != null) { try { Loading @@ -473,6 +512,17 @@ public final class TvInputManagerService extends SystemService { } } userState.serviceStateMap.clear(); // Clear everything else. userState.inputMap.clear(); userState.packageSet.clear(); userState.contentRatingSystemList.clear(); userState.clientStateMap.clear(); userState.callbackSet.clear(); userState.mainSessionToken = null; mUserStates.remove(userId); } } private ContentResolver getContentResolverForUser(int userId) { Loading Loading @@ -539,11 +589,6 @@ public final class TvInputManagerService extends SystemService { false, methodName, null); } private static boolean shouldMaintainConnection(ServiceState serviceState) { return !serviceState.sessionTokens.isEmpty() || serviceState.isHardware; // TODO: Find a way to maintain connection to hardware TV input service only when necessary. } private void updateServiceConnectionLocked(ComponentName component, int userId) { UserState userState = getOrCreateUserStateLocked(userId); ServiceState serviceState = userState.serviceStateMap.get(component); Loading @@ -557,8 +602,19 @@ public final class TvInputManagerService extends SystemService { } serviceState.reconnecting = false; } boolean maintainConnection = shouldMaintainConnection(serviceState); if (serviceState.service == null && maintainConnection && userId == mCurrentUserId) { boolean shouldBind; if (userId == mCurrentUserId) { shouldBind = !serviceState.sessionTokens.isEmpty() || serviceState.isHardware; } else { // For a non-current user, // if sessionTokens is not empty, it contains recording sessions only // because other sessions must have been removed while switching user // and non-recording sessions are not created by createSession(). shouldBind = !serviceState.sessionTokens.isEmpty(); } if (serviceState.service == null && shouldBind) { // This means that the service is not yet connected but its state indicates that we // have pending requests. Then, connect the service. if (serviceState.bound) { Loading @@ -575,7 +631,7 @@ public final class TvInputManagerService extends SystemService { i, serviceState.connection, Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE, new UserHandle(userId)); } else if (serviceState.service != null && !maintainConnection) { } else if (serviceState.service != null && !shouldBind) { // This means that the service is already connected but its state indicates that we have // nothing to do with it. Then, disconnect the service. if (DEBUG) { Loading Loading @@ -811,7 +867,7 @@ public final class TvInputManagerService extends SystemService { int oldState = inputState.state; inputState.state = state; if (serviceState != null && serviceState.service == null && shouldMaintainConnection(serviceState)) { && (!serviceState.sessionTokens.isEmpty() || serviceState.isHardware)) { // We don't notify state change while reconnecting. It should remain disconnected. return; } Loading Loading @@ -1080,6 +1136,13 @@ public final class TvInputManagerService extends SystemService { final long identity = Binder.clearCallingIdentity(); try { synchronized (mLock) { if (userId != mCurrentUserId && !isRecordingSession) { // A non-recording session of a backgroud (non-current) user // should not be created. // Let the client get onConnectionFailed callback for this case. sendSessionTokenToClientLocked(client, inputId, null, null, seq); return; } UserState userState = getOrCreateUserStateLocked(resolvedUserId); TvInputState inputState = userState.inputMap.get(inputId); if (inputState == null) { Loading Loading @@ -2073,27 +2136,7 @@ public final class TvInputManagerService extends SystemService { public void binderDied() { synchronized (mLock) { session = null; if (client != null) { try { client.onSessionReleased(seq); } catch(RemoteException e) { Slog.e(TAG, "error in onSessionReleased", e); } } // If there are any other sessions based on this session, they should be released. UserState userState = getOrCreateUserStateLocked(userId); for (SessionState sessionState : userState.sessionStateMap.values()) { if (sessionToken == sessionState.hardwareSessionToken) { releaseSessionLocked(sessionState.sessionToken, Process.SYSTEM_UID, userId); try { sessionState.client.onSessionReleased(sessionState.seq); } catch (RemoteException e) { Slog.e(TAG, "error in onSessionReleased", e); } } } removeSessionStateLocked(sessionToken, userId); clearSessionAndNotifyClientLocked(this); } } } Loading