Loading services/core/java/com/android/server/tv/TvInputManagerService.java +136 −43 Original line number Diff line number Diff line Loading @@ -213,11 +213,13 @@ public final class TvInputManagerService extends SystemService { Slog.e(TAG, "error in unregisterCallback", e); } } serviceState.mClients.clear(); serviceState.mClientTokens.clear(); mContext.unbindService(serviceState.mConnection); } userState.serviceStateMap.clear(); userState.clientStateMap.clear(); mUserStates.remove(userId); } } Loading Loading @@ -282,7 +284,7 @@ public final class TvInputManagerService extends SystemService { } serviceState.mReconnecting = false; } boolean isStateEmpty = serviceState.mClients.isEmpty() boolean isStateEmpty = serviceState.mClientTokens.isEmpty() && serviceState.mSessionTokens.isEmpty(); if (serviceState.mService == null && !isStateEmpty && userId == mCurrentUserId) { // This means that the service is not yet connected but its state indicates that we Loading Loading @@ -313,10 +315,22 @@ public final class TvInputManagerService extends SystemService { } } private ClientState createClientStateLocked(IBinder clientToken, int userId) { UserState userState = getUserStateLocked(userId); ClientState clientState = new ClientState(clientToken, userId); try { clientToken.linkToDeath(clientState, 0); } catch (RemoteException e) { Slog.e(TAG, "Client is already died."); } userState.clientStateMap.put(clientToken, clientState); return clientState; } private void createSessionInternalLocked(ITvInputService service, final IBinder sessionToken, final int userId) { final SessionState sessionState = getUserStateLocked(userId).sessionStateMap.get(sessionToken); final UserState userState = getUserStateLocked(userId); final SessionState sessionState = userState.sessionStateMap.get(sessionToken); if (DEBUG) { Slog.d(TAG, "createSessionInternalLocked(inputId=" + sessionState.mInputId + ")"); } Loading @@ -342,6 +356,14 @@ public final class TvInputManagerService extends SystemService { } catch (RemoteException e) { Slog.e(TAG, "Session is already died."); } IBinder clientToken = sessionState.mClient.asBinder(); ClientState clientState = userState.clientStateMap.get(clientToken); if (clientState == null) { clientState = createClientStateLocked(clientToken, userId); } clientState.mSessionTokens.add(sessionState.mSessionToken); sendSessionTokenToClientLocked(sessionState.mClient, sessionState.mInputId, sessionToken, channels[0], sessionState.mSeq, userId); } Loading Loading @@ -432,7 +454,16 @@ public final class TvInputManagerService extends SystemService { mLogHandler.obtainMessage(LogHandler.MSG_CLOSE_ENTRY, args).sendToTarget(); } // Also remove the session token from the session token list of the current service. // Also remove the session token from the session token list of the current client and // service. ClientState clientState = userState.clientStateMap.get(sessionState.mClient.asBinder()); if (clientState != null) { clientState.mSessionTokens.remove(sessionToken); if (clientState.isEmpty()) { userState.clientStateMap.remove(sessionState.mClient.asBinder()); } } ServiceState serviceState = userState.serviceStateMap.get(sessionState.mInputId); if (serviceState != null) { serviceState.mSessionTokens.remove(sessionToken); Loading @@ -440,11 +471,45 @@ public final class TvInputManagerService extends SystemService { updateServiceConnectionLocked(sessionState.mInputId, userId); } private void unregisterCallbackInternalLocked(IBinder clientToken, String inputId, int userId) { UserState userState = getUserStateLocked(userId); ClientState clientState = userState.clientStateMap.get(clientToken); if (clientState != null) { clientState.mInputIds.remove(inputId); if (clientState.isEmpty()) { userState.clientStateMap.remove(clientToken); } } ServiceState serviceState = userState.serviceStateMap.get(inputId); if (serviceState == null) { return; } // Remove this client from the client list and unregister the callback. serviceState.mClientTokens.remove(clientToken); if (!serviceState.mClientTokens.isEmpty()) { // We have other clients who want to keep the callback. Do this later. return; } if (serviceState.mService == null || serviceState.mCallback == null) { return; } try { serviceState.mService.unregisterCallback(serviceState.mCallback); } catch (RemoteException e) { Slog.e(TAG, "error in unregisterCallback", e); } finally { serviceState.mCallback = null; updateServiceConnectionLocked(inputId, userId); } } private void broadcastServiceAvailabilityChangedLocked(ServiceState serviceState) { for (IBinder iBinder : serviceState.mClients) { ITvInputClient client = ITvInputClient.Stub.asInterface(iBinder); for (IBinder clientToken : serviceState.mClientTokens) { try { client.onAvailabilityChanged( ITvInputClient.Stub.asInterface(clientToken).onAvailabilityChanged( serviceState.mTvInputInfo.getId(), serviceState.mAvailable); } catch (RemoteException e) { Slog.e(TAG, "error in onAvailabilityChanged", e); Loading Loading @@ -507,10 +572,19 @@ public final class TvInputManagerService extends SystemService { userState.inputMap.get(inputId), resolvedUserId); userState.serviceStateMap.put(inputId, serviceState); } IBinder iBinder = client.asBinder(); if (!serviceState.mClients.contains(iBinder)) { serviceState.mClients.add(iBinder); IBinder clientToken = client.asBinder(); if (!serviceState.mClientTokens.contains(clientToken)) { serviceState.mClientTokens.add(clientToken); } ClientState clientState = userState.clientStateMap.get(clientToken); if (clientState == null) { clientState = createClientStateLocked(clientToken, resolvedUserId); } if (!clientState.mInputIds.contains(inputId)) { clientState.mInputIds.add(inputId); } if (serviceState.mService != null) { if (serviceState.mCallback != null) { // We already handled. Loading Loading @@ -538,29 +612,7 @@ public final class TvInputManagerService extends SystemService { final long identity = Binder.clearCallingIdentity(); try { synchronized (mLock) { UserState userState = getUserStateLocked(resolvedUserId); ServiceState serviceState = userState.serviceStateMap.get(inputId); if (serviceState == null) { return; } // Remove this client from the client list and unregister the callback. serviceState.mClients.remove(client.asBinder()); if (!serviceState.mClients.isEmpty()) { // We have other clients who want to keep the callback. Do this later. return; } if (serviceState.mService == null || serviceState.mCallback == null) { return; } try { serviceState.mService.unregisterCallback(serviceState.mCallback); } catch (RemoteException e) { Slog.e(TAG, "error in unregisterCallback", e); } finally { serviceState.mCallback = null; updateServiceConnectionLocked(inputId, resolvedUserId); } unregisterCallbackInternalLocked(client.asBinder(), inputId, resolvedUserId); } } finally { Binder.restoreCallingIdentity(identity); Loading Loading @@ -591,8 +643,8 @@ public final class TvInputManagerService extends SystemService { // Create a new session token and a session state. IBinder sessionToken = new Binder(); SessionState sessionState = new SessionState( sessionToken, inputId, client, seq, callingUid, resolvedUserId); SessionState sessionState = new SessionState(sessionToken, inputId, client, seq, callingUid, resolvedUserId); // Add them to the global session state map of the current user. userState.sessionStateMap.put(sessionToken, sessionState); Loading Loading @@ -844,6 +896,10 @@ public final class TvInputManagerService extends SystemService { // A mapping from the TV input id to its TvInputInfo. private final Map<String, TvInputInfo> inputMap = new HashMap<String,TvInputInfo>(); // A mapping from the token of a client to its state. private final Map<IBinder, ClientState> clientStateMap = new HashMap<IBinder, ClientState>(); // A mapping from the name of a TV input service to its state. private final Map<String, ServiceState> serviceStateMap = new HashMap<String, ServiceState>(); Loading @@ -853,9 +909,46 @@ public final class TvInputManagerService extends SystemService { new HashMap<IBinder, SessionState>(); } private final class ClientState implements IBinder.DeathRecipient { private final List<String> mInputIds = new ArrayList<String>(); private final List<IBinder> mSessionTokens = new ArrayList<IBinder>(); private IBinder mClientToken; private final int mUserId; ClientState(IBinder clientToken, int userId) { mClientToken = clientToken; mUserId = userId; } public boolean isEmpty() { return mInputIds.isEmpty() && mSessionTokens.isEmpty(); } @Override public void binderDied() { synchronized (mLock) { UserState userState = getUserStateLocked(mUserId); // DO NOT remove the client state of clientStateMap in this method. It will be // removed in releaseSessionLocked() or unregisterCallbackInternalLocked(). ClientState clientState = userState.clientStateMap.get(mClientToken); if (clientState != null) { while (clientState.mSessionTokens.size() > 0) { releaseSessionLocked( clientState.mSessionTokens.get(0), Process.SYSTEM_UID, mUserId); } while (clientState.mInputIds.size() > 0) { unregisterCallbackInternalLocked( mClientToken, clientState.mInputIds.get(0), mUserId); } } mClientToken = null; } } } private final class ServiceState { // TODO: need to implement DeathRecipient for clients. private final List<IBinder> mClients = new ArrayList<IBinder>(); private final List<IBinder> mClientTokens = new ArrayList<IBinder>(); private final List<IBinder> mSessionTokens = new ArrayList<IBinder>(); private final ServiceConnection mConnection; private final TvInputInfo mTvInputInfo; Loading @@ -878,13 +971,13 @@ public final class TvInputManagerService extends SystemService { private final int mSeq; private final int mCallingUid; private final int mUserId; private final IBinder mToken; private final IBinder mSessionToken; private ITvInputSession mSession; private Uri mLogUri; private SessionState(IBinder token, String inputId, ITvInputClient client, int seq, private SessionState(IBinder sessionToken, String inputId, ITvInputClient client, int seq, int callingUid, int userId) { mToken = token; mSessionToken = sessionToken; mInputId = inputId; mClient = client; mSeq = seq; Loading @@ -903,7 +996,7 @@ public final class TvInputManagerService extends SystemService { Slog.e(TAG, "error in onSessionReleased", e); } } removeSessionStateLocked(mToken, mUserId); removeSessionStateLocked(mSessionToken, mUserId); } } } Loading @@ -927,7 +1020,7 @@ public final class TvInputManagerService extends SystemService { serviceState.mService = ITvInputService.Stub.asInterface(service); // Register a callback, if we need to. if (!serviceState.mClients.isEmpty() && serviceState.mCallback == null) { if (!serviceState.mClientTokens.isEmpty() && serviceState.mCallback == null) { serviceState.mCallback = new ServiceCallback(mUserId); try { serviceState.mService.registerCallback(serviceState.mCallback); Loading Loading
services/core/java/com/android/server/tv/TvInputManagerService.java +136 −43 Original line number Diff line number Diff line Loading @@ -213,11 +213,13 @@ public final class TvInputManagerService extends SystemService { Slog.e(TAG, "error in unregisterCallback", e); } } serviceState.mClients.clear(); serviceState.mClientTokens.clear(); mContext.unbindService(serviceState.mConnection); } userState.serviceStateMap.clear(); userState.clientStateMap.clear(); mUserStates.remove(userId); } } Loading Loading @@ -282,7 +284,7 @@ public final class TvInputManagerService extends SystemService { } serviceState.mReconnecting = false; } boolean isStateEmpty = serviceState.mClients.isEmpty() boolean isStateEmpty = serviceState.mClientTokens.isEmpty() && serviceState.mSessionTokens.isEmpty(); if (serviceState.mService == null && !isStateEmpty && userId == mCurrentUserId) { // This means that the service is not yet connected but its state indicates that we Loading Loading @@ -313,10 +315,22 @@ public final class TvInputManagerService extends SystemService { } } private ClientState createClientStateLocked(IBinder clientToken, int userId) { UserState userState = getUserStateLocked(userId); ClientState clientState = new ClientState(clientToken, userId); try { clientToken.linkToDeath(clientState, 0); } catch (RemoteException e) { Slog.e(TAG, "Client is already died."); } userState.clientStateMap.put(clientToken, clientState); return clientState; } private void createSessionInternalLocked(ITvInputService service, final IBinder sessionToken, final int userId) { final SessionState sessionState = getUserStateLocked(userId).sessionStateMap.get(sessionToken); final UserState userState = getUserStateLocked(userId); final SessionState sessionState = userState.sessionStateMap.get(sessionToken); if (DEBUG) { Slog.d(TAG, "createSessionInternalLocked(inputId=" + sessionState.mInputId + ")"); } Loading @@ -342,6 +356,14 @@ public final class TvInputManagerService extends SystemService { } catch (RemoteException e) { Slog.e(TAG, "Session is already died."); } IBinder clientToken = sessionState.mClient.asBinder(); ClientState clientState = userState.clientStateMap.get(clientToken); if (clientState == null) { clientState = createClientStateLocked(clientToken, userId); } clientState.mSessionTokens.add(sessionState.mSessionToken); sendSessionTokenToClientLocked(sessionState.mClient, sessionState.mInputId, sessionToken, channels[0], sessionState.mSeq, userId); } Loading Loading @@ -432,7 +454,16 @@ public final class TvInputManagerService extends SystemService { mLogHandler.obtainMessage(LogHandler.MSG_CLOSE_ENTRY, args).sendToTarget(); } // Also remove the session token from the session token list of the current service. // Also remove the session token from the session token list of the current client and // service. ClientState clientState = userState.clientStateMap.get(sessionState.mClient.asBinder()); if (clientState != null) { clientState.mSessionTokens.remove(sessionToken); if (clientState.isEmpty()) { userState.clientStateMap.remove(sessionState.mClient.asBinder()); } } ServiceState serviceState = userState.serviceStateMap.get(sessionState.mInputId); if (serviceState != null) { serviceState.mSessionTokens.remove(sessionToken); Loading @@ -440,11 +471,45 @@ public final class TvInputManagerService extends SystemService { updateServiceConnectionLocked(sessionState.mInputId, userId); } private void unregisterCallbackInternalLocked(IBinder clientToken, String inputId, int userId) { UserState userState = getUserStateLocked(userId); ClientState clientState = userState.clientStateMap.get(clientToken); if (clientState != null) { clientState.mInputIds.remove(inputId); if (clientState.isEmpty()) { userState.clientStateMap.remove(clientToken); } } ServiceState serviceState = userState.serviceStateMap.get(inputId); if (serviceState == null) { return; } // Remove this client from the client list and unregister the callback. serviceState.mClientTokens.remove(clientToken); if (!serviceState.mClientTokens.isEmpty()) { // We have other clients who want to keep the callback. Do this later. return; } if (serviceState.mService == null || serviceState.mCallback == null) { return; } try { serviceState.mService.unregisterCallback(serviceState.mCallback); } catch (RemoteException e) { Slog.e(TAG, "error in unregisterCallback", e); } finally { serviceState.mCallback = null; updateServiceConnectionLocked(inputId, userId); } } private void broadcastServiceAvailabilityChangedLocked(ServiceState serviceState) { for (IBinder iBinder : serviceState.mClients) { ITvInputClient client = ITvInputClient.Stub.asInterface(iBinder); for (IBinder clientToken : serviceState.mClientTokens) { try { client.onAvailabilityChanged( ITvInputClient.Stub.asInterface(clientToken).onAvailabilityChanged( serviceState.mTvInputInfo.getId(), serviceState.mAvailable); } catch (RemoteException e) { Slog.e(TAG, "error in onAvailabilityChanged", e); Loading Loading @@ -507,10 +572,19 @@ public final class TvInputManagerService extends SystemService { userState.inputMap.get(inputId), resolvedUserId); userState.serviceStateMap.put(inputId, serviceState); } IBinder iBinder = client.asBinder(); if (!serviceState.mClients.contains(iBinder)) { serviceState.mClients.add(iBinder); IBinder clientToken = client.asBinder(); if (!serviceState.mClientTokens.contains(clientToken)) { serviceState.mClientTokens.add(clientToken); } ClientState clientState = userState.clientStateMap.get(clientToken); if (clientState == null) { clientState = createClientStateLocked(clientToken, resolvedUserId); } if (!clientState.mInputIds.contains(inputId)) { clientState.mInputIds.add(inputId); } if (serviceState.mService != null) { if (serviceState.mCallback != null) { // We already handled. Loading Loading @@ -538,29 +612,7 @@ public final class TvInputManagerService extends SystemService { final long identity = Binder.clearCallingIdentity(); try { synchronized (mLock) { UserState userState = getUserStateLocked(resolvedUserId); ServiceState serviceState = userState.serviceStateMap.get(inputId); if (serviceState == null) { return; } // Remove this client from the client list and unregister the callback. serviceState.mClients.remove(client.asBinder()); if (!serviceState.mClients.isEmpty()) { // We have other clients who want to keep the callback. Do this later. return; } if (serviceState.mService == null || serviceState.mCallback == null) { return; } try { serviceState.mService.unregisterCallback(serviceState.mCallback); } catch (RemoteException e) { Slog.e(TAG, "error in unregisterCallback", e); } finally { serviceState.mCallback = null; updateServiceConnectionLocked(inputId, resolvedUserId); } unregisterCallbackInternalLocked(client.asBinder(), inputId, resolvedUserId); } } finally { Binder.restoreCallingIdentity(identity); Loading Loading @@ -591,8 +643,8 @@ public final class TvInputManagerService extends SystemService { // Create a new session token and a session state. IBinder sessionToken = new Binder(); SessionState sessionState = new SessionState( sessionToken, inputId, client, seq, callingUid, resolvedUserId); SessionState sessionState = new SessionState(sessionToken, inputId, client, seq, callingUid, resolvedUserId); // Add them to the global session state map of the current user. userState.sessionStateMap.put(sessionToken, sessionState); Loading Loading @@ -844,6 +896,10 @@ public final class TvInputManagerService extends SystemService { // A mapping from the TV input id to its TvInputInfo. private final Map<String, TvInputInfo> inputMap = new HashMap<String,TvInputInfo>(); // A mapping from the token of a client to its state. private final Map<IBinder, ClientState> clientStateMap = new HashMap<IBinder, ClientState>(); // A mapping from the name of a TV input service to its state. private final Map<String, ServiceState> serviceStateMap = new HashMap<String, ServiceState>(); Loading @@ -853,9 +909,46 @@ public final class TvInputManagerService extends SystemService { new HashMap<IBinder, SessionState>(); } private final class ClientState implements IBinder.DeathRecipient { private final List<String> mInputIds = new ArrayList<String>(); private final List<IBinder> mSessionTokens = new ArrayList<IBinder>(); private IBinder mClientToken; private final int mUserId; ClientState(IBinder clientToken, int userId) { mClientToken = clientToken; mUserId = userId; } public boolean isEmpty() { return mInputIds.isEmpty() && mSessionTokens.isEmpty(); } @Override public void binderDied() { synchronized (mLock) { UserState userState = getUserStateLocked(mUserId); // DO NOT remove the client state of clientStateMap in this method. It will be // removed in releaseSessionLocked() or unregisterCallbackInternalLocked(). ClientState clientState = userState.clientStateMap.get(mClientToken); if (clientState != null) { while (clientState.mSessionTokens.size() > 0) { releaseSessionLocked( clientState.mSessionTokens.get(0), Process.SYSTEM_UID, mUserId); } while (clientState.mInputIds.size() > 0) { unregisterCallbackInternalLocked( mClientToken, clientState.mInputIds.get(0), mUserId); } } mClientToken = null; } } } private final class ServiceState { // TODO: need to implement DeathRecipient for clients. private final List<IBinder> mClients = new ArrayList<IBinder>(); private final List<IBinder> mClientTokens = new ArrayList<IBinder>(); private final List<IBinder> mSessionTokens = new ArrayList<IBinder>(); private final ServiceConnection mConnection; private final TvInputInfo mTvInputInfo; Loading @@ -878,13 +971,13 @@ public final class TvInputManagerService extends SystemService { private final int mSeq; private final int mCallingUid; private final int mUserId; private final IBinder mToken; private final IBinder mSessionToken; private ITvInputSession mSession; private Uri mLogUri; private SessionState(IBinder token, String inputId, ITvInputClient client, int seq, private SessionState(IBinder sessionToken, String inputId, ITvInputClient client, int seq, int callingUid, int userId) { mToken = token; mSessionToken = sessionToken; mInputId = inputId; mClient = client; mSeq = seq; Loading @@ -903,7 +996,7 @@ public final class TvInputManagerService extends SystemService { Slog.e(TAG, "error in onSessionReleased", e); } } removeSessionStateLocked(mToken, mUserId); removeSessionStateLocked(mSessionToken, mUserId); } } } Loading @@ -927,7 +1020,7 @@ public final class TvInputManagerService extends SystemService { serviceState.mService = ITvInputService.Stub.asInterface(service); // Register a callback, if we need to. if (!serviceState.mClients.isEmpty() && serviceState.mCallback == null) { if (!serviceState.mClientTokens.isEmpty() && serviceState.mCallback == null) { serviceState.mCallback = new ServiceCallback(mUserId); try { serviceState.mService.registerCallback(serviceState.mCallback); Loading