Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 993f81e2 authored by Dongwon Kang's avatar Dongwon Kang
Browse files

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
parent f1702487
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -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);

+22 −1
Original line number Diff line number Diff line
@@ -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);
        }
    }

+17 −4
Original line number Diff line number Diff line
@@ -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);