Merge "TIF: Keep recording sessions while changing user" into nyc-dev
This commit is contained in:
@@ -415,7 +415,38 @@ public final class TvInputManagerService extends SystemService {
|
|||||||
if (mCurrentUserId == userId) {
|
if (mCurrentUserId == userId) {
|
||||||
return;
|
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;
|
mCurrentUserId = userId;
|
||||||
getOrCreateUserStateLocked(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) {
|
private void removeUser(int userId) {
|
||||||
synchronized (mLock) {
|
synchronized (mLock) {
|
||||||
UserState userState = mUserStates.get(userId);
|
UserState userState = mUserStates.get(userId);
|
||||||
if (userState == null) {
|
if (userState == null) {
|
||||||
return;
|
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.
|
// Clear everything else.
|
||||||
userState.inputMap.clear();
|
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) {
|
private ContentResolver getContentResolverForUser(int userId) {
|
||||||
UserHandle user = new UserHandle(userId);
|
UserHandle user = new UserHandle(userId);
|
||||||
Context context;
|
Context context;
|
||||||
@@ -539,11 +589,6 @@ public final class TvInputManagerService extends SystemService {
|
|||||||
false, methodName, null);
|
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) {
|
private void updateServiceConnectionLocked(ComponentName component, int userId) {
|
||||||
UserState userState = getOrCreateUserStateLocked(userId);
|
UserState userState = getOrCreateUserStateLocked(userId);
|
||||||
ServiceState serviceState = userState.serviceStateMap.get(component);
|
ServiceState serviceState = userState.serviceStateMap.get(component);
|
||||||
@@ -557,8 +602,19 @@ public final class TvInputManagerService extends SystemService {
|
|||||||
}
|
}
|
||||||
serviceState.reconnecting = false;
|
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
|
// This means that the service is not yet connected but its state indicates that we
|
||||||
// have pending requests. Then, connect the service.
|
// have pending requests. Then, connect the service.
|
||||||
if (serviceState.bound) {
|
if (serviceState.bound) {
|
||||||
@@ -575,7 +631,7 @@ public final class TvInputManagerService extends SystemService {
|
|||||||
i, serviceState.connection,
|
i, serviceState.connection,
|
||||||
Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE,
|
Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE,
|
||||||
new UserHandle(userId));
|
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
|
// This means that the service is already connected but its state indicates that we have
|
||||||
// nothing to do with it. Then, disconnect the service.
|
// nothing to do with it. Then, disconnect the service.
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
@@ -811,7 +867,7 @@ public final class TvInputManagerService extends SystemService {
|
|||||||
int oldState = inputState.state;
|
int oldState = inputState.state;
|
||||||
inputState.state = state;
|
inputState.state = state;
|
||||||
if (serviceState != null && serviceState.service == null
|
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.
|
// We don't notify state change while reconnecting. It should remain disconnected.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1080,6 +1136,13 @@ public final class TvInputManagerService extends SystemService {
|
|||||||
final long identity = Binder.clearCallingIdentity();
|
final long identity = Binder.clearCallingIdentity();
|
||||||
try {
|
try {
|
||||||
synchronized (mLock) {
|
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);
|
UserState userState = getOrCreateUserStateLocked(resolvedUserId);
|
||||||
TvInputState inputState = userState.inputMap.get(inputId);
|
TvInputState inputState = userState.inputMap.get(inputId);
|
||||||
if (inputState == null) {
|
if (inputState == null) {
|
||||||
@@ -2073,27 +2136,7 @@ public final class TvInputManagerService extends SystemService {
|
|||||||
public void binderDied() {
|
public void binderDied() {
|
||||||
synchronized (mLock) {
|
synchronized (mLock) {
|
||||||
session = null;
|
session = null;
|
||||||
if (client != null) {
|
clearSessionAndNotifyClientLocked(this);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user