TIF: fix a race condition when TvInputManager is initialized
Currently, TvInputManagerService notifies the initial state of each input via TvInputManagetCallback#onInputStateChanged after TvInputManager is created. However, this is racy because the client may call methods like getTvInputState() before the initialization. This patch makes sure that the client gets the control when the initialization finishes completely. Bug: 18419452 Change-Id: I5d8141c20984013e68f2809120710c670557c9ad
This commit is contained in:
@@ -38,6 +38,7 @@ import android.view.Surface;
|
||||
interface ITvInputManager {
|
||||
List<TvInputInfo> getTvInputList(int userId);
|
||||
TvInputInfo getTvInputInfo(in String inputId, int userId);
|
||||
int getTvInputState(in String inputId, int userId);
|
||||
|
||||
List<TvContentRatingSystemInfo> getTvContentRatingSystemList(int userId);
|
||||
|
||||
|
||||
@@ -71,6 +71,17 @@ public final class TvInputManager {
|
||||
*/
|
||||
public static final int VIDEO_UNAVAILABLE_REASON_BUFFERING = VIDEO_UNAVAILABLE_REASON_END;
|
||||
|
||||
/**
|
||||
* The TV input is in unknown state.
|
||||
* <p>
|
||||
* State for denoting unknown TV input state. The typical use case is when a requested TV
|
||||
* input is removed from the device or it is not registered. Used in
|
||||
* {@code ITvInputManager.getTvInputState()}.
|
||||
* </p>
|
||||
* @hide
|
||||
*/
|
||||
public static final int INPUT_STATE_UNKNOWN = -1;
|
||||
|
||||
/**
|
||||
* The TV input is connected.
|
||||
* <p>
|
||||
@@ -751,9 +762,19 @@ public final class TvInputManager {
|
||||
try {
|
||||
if (mService != null) {
|
||||
mService.registerCallback(mManagerCallback, mUserId);
|
||||
List<TvInputInfo> infos = mService.getTvInputList(mUserId);
|
||||
synchronized (mLock) {
|
||||
for (TvInputInfo info : infos) {
|
||||
String inputId = info.getId();
|
||||
int state = mService.getTvInputState(inputId, mUserId);
|
||||
if (state != INPUT_STATE_UNKNOWN) {
|
||||
mStateMap.put(inputId, state);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "mService.registerCallback failed: " + e);
|
||||
Log.e(TAG, "TvInputManager initialization failed: " + e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ package com.android.server.tv;
|
||||
import static android.media.tv.TvInputManager.INPUT_STATE_CONNECTED;
|
||||
import static android.media.tv.TvInputManager.INPUT_STATE_CONNECTED_STANDBY;
|
||||
import static android.media.tv.TvInputManager.INPUT_STATE_DISCONNECTED;
|
||||
import static android.media.tv.TvInputManager.INPUT_STATE_UNKNOWN;
|
||||
|
||||
import android.app.ActivityManager;
|
||||
import android.content.BroadcastReceiver;
|
||||
@@ -778,6 +779,22 @@ public final class TvInputManagerService extends SystemService {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTvInputState(String inputId, int userId) {
|
||||
final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(),
|
||||
Binder.getCallingUid(), userId, "getTvInputState");
|
||||
final long identity = Binder.clearCallingIdentity();
|
||||
try {
|
||||
synchronized (mLock) {
|
||||
UserState userState = getUserStateLocked(resolvedUserId);
|
||||
TvInputState state = userState.inputMap.get(inputId);
|
||||
return state == null ? INPUT_STATE_UNKNOWN : state.state;
|
||||
}
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(identity);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<TvContentRatingSystemInfo> getTvContentRatingSystemList(int userId) {
|
||||
final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(),
|
||||
@@ -816,10 +833,6 @@ public final class TvInputManagerService extends SystemService {
|
||||
} catch (RemoteException e) {
|
||||
Slog.e(TAG, "client process has already died", e);
|
||||
}
|
||||
for (TvInputState state : userState.inputMap.values()) {
|
||||
notifyInputStateChangedLocked(userState, state.info.getId(), state.state,
|
||||
callback);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(identity);
|
||||
|
||||
Reference in New Issue
Block a user