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:
Dongwon Kang
2014-11-27 19:34:18 +09:00
parent f17024873b
commit 993f81e238
3 changed files with 40 additions and 5 deletions

View File

@@ -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);

View File

@@ -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);
}
}

View File

@@ -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);