Merge "TIF: Keep recording sessions while changing user" into nyc-dev

This commit is contained in:
Shubang Lu
2016-05-05 18:20:12 +00:00
committed by Android (Google) Code Review

View File

@@ -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);
@@ -426,13 +457,61 @@ 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);
// Release all created sessions.
for (SessionState state : userState.sessionStateMap.values()) {
if (state.session != null) {
try {
state.session.release();
} catch (RemoteException e) {
Slog.e(TAG, "error in release", e);
}
}
}
userState.sessionStateMap.clear();
// Unregister all callbacks and unbind all services.
for (ServiceState serviceState : userState.serviceStateMap.values()) {
if (serviceState.service != null) {
if (serviceState.callback != null) {
try {
serviceState.service.unregisterCallback(serviceState.callback);
} catch (RemoteException e) {
Slog.e(TAG, "error in unregisterCallback", e);
}
}
mContext.unbindService(serviceState.connection);
}
}
userState.serviceStateMap.clear();
// Clear everything else.
userState.inputMap.clear();
@@ -446,35 +525,6 @@ public final class TvInputManagerService extends SystemService {
}
}
private void clearSessionAndServiceStatesLocked(UserState userState) {
// Release created sessions.
for (SessionState state : userState.sessionStateMap.values()) {
if (state.session != null) {
try {
state.session.release();
} catch (RemoteException e) {
Slog.e(TAG, "error in release", e);
}
}
}
userState.sessionStateMap.clear();
// Unregister all callbacks and unbind all services.
for (ServiceState serviceState : userState.serviceStateMap.values()) {
if (serviceState.service != null) {
if (serviceState.callback != null) {
try {
serviceState.service.unregisterCallback(serviceState.callback);
} catch (RemoteException e) {
Slog.e(TAG, "error in unregisterCallback", e);
}
}
mContext.unbindService(serviceState.connection);
}
}
userState.serviceStateMap.clear();
}
private ContentResolver getContentResolverForUser(int userId) {
UserHandle user = new UserHandle(userId);
Context context;
@@ -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);
@@ -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) {
@@ -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) {
@@ -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;
}
@@ -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) {
@@ -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);
}
}
}