From 993f81e2380da210c27e1e957ac1bdca3a99100a Mon Sep 17 00:00:00 2001 From: Dongwon Kang Date: Thu, 27 Nov 2014 19:34:18 +0900 Subject: [PATCH] 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 --- .../android/media/tv/ITvInputManager.aidl | 1 + .../java/android/media/tv/TvInputManager.java | 23 ++++++++++++++++++- .../server/tv/TvInputManagerService.java | 21 +++++++++++++---- 3 files changed, 40 insertions(+), 5 deletions(-) diff --git a/media/java/android/media/tv/ITvInputManager.aidl b/media/java/android/media/tv/ITvInputManager.aidl index 6ca794ebc6524..21549c901ae7f 100644 --- a/media/java/android/media/tv/ITvInputManager.aidl +++ b/media/java/android/media/tv/ITvInputManager.aidl @@ -38,6 +38,7 @@ import android.view.Surface; interface ITvInputManager { List getTvInputList(int userId); TvInputInfo getTvInputInfo(in String inputId, int userId); + int getTvInputState(in String inputId, int userId); List getTvContentRatingSystemList(int userId); diff --git a/media/java/android/media/tv/TvInputManager.java b/media/java/android/media/tv/TvInputManager.java index de9d54f8d3770..21fc429180274 100644 --- a/media/java/android/media/tv/TvInputManager.java +++ b/media/java/android/media/tv/TvInputManager.java @@ -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. + *

+ * 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()}. + *

+ * @hide + */ + public static final int INPUT_STATE_UNKNOWN = -1; + /** * The TV input is connected. *

@@ -751,9 +762,19 @@ public final class TvInputManager { try { if (mService != null) { mService.registerCallback(mManagerCallback, mUserId); + List 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); } } diff --git a/services/core/java/com/android/server/tv/TvInputManagerService.java b/services/core/java/com/android/server/tv/TvInputManagerService.java index dc355c473e0e8..5ab3fa1e84864 100644 --- a/services/core/java/com/android/server/tv/TvInputManagerService.java +++ b/services/core/java/com/android/server/tv/TvInputManagerService.java @@ -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 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);