TvInputManagerService.java revision 7de5e234715a3baa8905afa3dd0c5009af64541f
13957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo/*
23957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo * Copyright (C) 2014 The Android Open Source Project
33957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo *
43957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo * Licensed under the Apache License, Version 2.0 (the "License");
53957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo * you may not use this file except in compliance with the License.
63957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo * You may obtain a copy of the License at
73957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo *
83957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo *      http://www.apache.org/licenses/LICENSE-2.0
93957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo *
103957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo * Unless required by applicable law or agreed to in writing, software
113957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo * distributed under the License is distributed on an "AS IS" BASIS,
123957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
133957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo * See the License for the specific language governing permissions and
143957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo * limitations under the License.
153957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo */
163957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
173957091ba8f08c02b5e781098cb955a5f697a1ffJae Seopackage com.android.server.tv;
183957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
193957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.app.ActivityManager;
203957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.content.BroadcastReceiver;
213957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.content.ComponentName;
223957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.content.Context;
233957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.content.Intent;
243957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.content.IntentFilter;
253957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.content.ServiceConnection;
263957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.content.pm.PackageManager;
273957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.content.pm.ResolveInfo;
283957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.content.pm.ServiceInfo;
293957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.net.Uri;
303957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.os.Binder;
313957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.os.IBinder;
323957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.os.Process;
333957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.os.RemoteException;
343957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.os.UserHandle;
353957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.tv.ITvInputClient;
363957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.tv.ITvInputManager;
373957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.tv.ITvInputService;
383957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.tv.ITvInputServiceCallback;
393957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.tv.ITvInputSession;
403957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.tv.ITvInputSessionCallback;
413957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.tv.TvInputInfo;
423957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.tv.TvInputService;
433957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.util.ArrayMap;
443957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.util.Log;
453957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.util.SparseArray;
463957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.view.Surface;
473957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
483957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport com.android.internal.content.PackageMonitor;
493957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport com.android.server.SystemService;
503957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
513957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport java.util.ArrayList;
523957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport java.util.HashMap;
533957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport java.util.List;
543957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport java.util.Map;
553957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
563957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo/** This class provides a system service that manages television inputs. */
573957091ba8f08c02b5e781098cb955a5f697a1ffJae Seopublic final class TvInputManagerService extends SystemService {
583957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    // STOPSHIP: Turn debugging off.
593957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private static final boolean DEBUG = true;
603957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private static final String TAG = "TvInputManagerService";
613957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
623957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private final Context mContext;
633957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
643957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    // A global lock.
653957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private final Object mLock = new Object();
663957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
673957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    // ID of the current user.
683957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private int mCurrentUserId = UserHandle.USER_OWNER;
693957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
703957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    // A map from user id to UserState.
713957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private final SparseArray<UserState> mUserStates = new SparseArray<UserState>();
723957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
733957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    public TvInputManagerService(Context context) {
743957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        super(context);
753957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        mContext = context;
763957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        registerBroadcastReceivers();
773957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        synchronized (mLock) {
783957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            mUserStates.put(mCurrentUserId, new UserState());
793957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            buildTvInputListLocked(mCurrentUserId);
803957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
813957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
823957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
833957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    @Override
843957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    public void onStart() {
853957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        publishBinderService(Context.TV_INPUT_SERVICE, new BinderService());
863957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
873957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
883957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private void registerBroadcastReceivers() {
893957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        PackageMonitor monitor = new PackageMonitor() {
903957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            @Override
913957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            public void onSomePackagesChanged() {
923957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                synchronized (mLock) {
933957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    buildTvInputListLocked(mCurrentUserId);
943957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
953957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
963957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        };
973957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        monitor.register(mContext, null, UserHandle.ALL, true);
983957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
993957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        IntentFilter intentFilter = new IntentFilter();
1003957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
1013957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        intentFilter.addAction(Intent.ACTION_USER_REMOVED);
1023957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        mContext.registerReceiverAsUser(new BroadcastReceiver() {
1033957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            @Override
1043957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            public void onReceive(Context context, Intent intent) {
1053957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                String action = intent.getAction();
1063957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                if (Intent.ACTION_USER_SWITCHED.equals(action)) {
1073957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    switchUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
1083957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                } else if (Intent.ACTION_USER_REMOVED.equals(action)) {
1093957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    removeUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
1103957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
1113957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
1123957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }, UserHandle.ALL, intentFilter, null, null);
1133957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
1143957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
1153957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private void buildTvInputListLocked(int userId) {
1163957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        UserState userState = getUserStateLocked(userId);
1173957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        userState.inputList.clear();
1183957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
1193957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        PackageManager pm = mContext.getPackageManager();
1203957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        List<ResolveInfo> services = pm.queryIntentServices(
1213957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                new Intent(TvInputService.SERVICE_INTERFACE), PackageManager.GET_SERVICES);
1223957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        for (ResolveInfo ri : services) {
1233957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            ServiceInfo si = ri.serviceInfo;
1243957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            if (!android.Manifest.permission.BIND_TV_INPUT.equals(si.permission)) {
1253957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                Log.w(TAG, "Skipping TV input " + si.name + ": it does not require the permission "
1263957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                        + android.Manifest.permission.BIND_TV_INPUT);
1273957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                continue;
1283957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
1293957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            TvInputInfo info = new TvInputInfo(ri);
1303957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            userState.inputList.add(info);
1313957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
1323957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
1333957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
1343957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private void switchUser(int userId) {
1353957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        synchronized (mLock) {
1363957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            if (mCurrentUserId == userId) {
1373957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                return;
1383957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
1393957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            // final int oldUserId = mCurrentUserId;
1403957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            // TODO: Release services and sessions in the old user state, if needed.
1413957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            mCurrentUserId = userId;
1423957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
1433957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            UserState userState = mUserStates.get(userId);
1443957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            if (userState == null) {
1453957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                userState = new UserState();
1463957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
1473957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            mUserStates.put(userId, userState);
1483957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            buildTvInputListLocked(userId);
1493957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
1503957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
1513957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
1523957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private void removeUser(int userId) {
1533957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        synchronized (mLock) {
154b06cb8870f0407f18bb1225065a93aba2a5de2bfJae Seo            UserState userState = mUserStates.get(userId);
155b06cb8870f0407f18bb1225065a93aba2a5de2bfJae Seo            if (userState == null) {
156b06cb8870f0407f18bb1225065a93aba2a5de2bfJae Seo                return;
157b06cb8870f0407f18bb1225065a93aba2a5de2bfJae Seo            }
1583957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            // Release created sessions.
1593957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            for (SessionState state : userState.sessionStateMap.values()) {
1603957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                if (state.session != null) {
1613957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    try {
1623957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                        state.session.release();
1633957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    } catch (RemoteException e) {
1643957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                        Log.e(TAG, "error in release", e);
1653957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    }
1663957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
1673957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
1683957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            userState.sessionStateMap.clear();
1693957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
1703957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            // Unregister all callbacks and unbind all services.
1713957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            for (ServiceState serviceState : userState.serviceStateMap.values()) {
1723957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                if (serviceState.callback != null) {
1733957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    try {
1743957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                        serviceState.service.unregisterCallback(serviceState.callback);
1753957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    } catch (RemoteException e) {
1763957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                        Log.e(TAG, "error in unregisterCallback", e);
1773957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    }
1783957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
1793957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                serviceState.clients.clear();
1803957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                mContext.unbindService(serviceState.connection);
1813957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
1823957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            userState.serviceStateMap.clear();
1833957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
1843957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            mUserStates.remove(userId);
1853957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
1863957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
1873957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
1883957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private UserState getUserStateLocked(int userId) {
1893957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        UserState userState = mUserStates.get(userId);
1903957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        if (userState == null) {
1913957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            throw new IllegalStateException("User state not found for user ID " + userId);
1923957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
1933957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        return userState;
1943957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
1953957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
1963957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private ServiceState getServiceStateLocked(ComponentName name, int userId) {
1973957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        UserState userState = getUserStateLocked(userId);
1983957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        ServiceState serviceState = userState.serviceStateMap.get(name);
1993957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        if (serviceState == null) {
2007de5e234715a3baa8905afa3dd0c5009af64541fSungsoo Lim            throw new IllegalStateException("Service state not found for " + name + " (userId="
2017de5e234715a3baa8905afa3dd0c5009af64541fSungsoo Lim                    + userId + ")");
2023957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
2033957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        return serviceState;
2043957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
2053957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
2063957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private ITvInputSession getSessionLocked(IBinder sessionToken, int callingUid, int userId) {
2073957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        UserState userState = getUserStateLocked(userId);
2083957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        SessionState sessionState = userState.sessionStateMap.get(sessionToken);
2093957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        if (sessionState == null) {
2103957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            throw new IllegalArgumentException("Session state not found for token " + sessionToken);
2113957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
2123957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        // Only the application that requested this session or the system can access it.
2133957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        if (callingUid != Process.SYSTEM_UID && callingUid != sessionState.callingUid) {
2143957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            throw new SecurityException("Illegal access to the session with token " + sessionToken
2153957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    + " from uid " + callingUid);
2163957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
2173957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        ITvInputSession session = sessionState.session;
2183957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        if (session == null) {
2193957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            throw new IllegalStateException("Session not yet created for token " + sessionToken);
2203957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
2213957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        return session;
2223957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
2233957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
2243957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private int resolveCallingUserId(int callingPid, int callingUid, int requestedUserId,
2253957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            String methodName) {
2263957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        return ActivityManager.handleIncomingUser(callingPid, callingUid, requestedUserId, false,
2273957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                false, methodName, null);
2283957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
2293957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
2303957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private void updateServiceConnectionLocked(ComponentName name, int userId) {
2313957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        UserState userState = getUserStateLocked(userId);
2323957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        ServiceState serviceState = userState.serviceStateMap.get(name);
2333957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        if (serviceState == null) {
2343957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            return;
2353957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
2367de5e234715a3baa8905afa3dd0c5009af64541fSungsoo Lim        boolean isStateEmpty = serviceState.clients.isEmpty()
2377de5e234715a3baa8905afa3dd0c5009af64541fSungsoo Lim                && serviceState.sessionTokens.isEmpty();
2383957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        if (serviceState.service == null && !isStateEmpty && userId == mCurrentUserId) {
2393957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            // This means that the service is not yet connected but its state indicates that we
2403957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            // have pending requests. Then, connect the service.
2413957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            if (serviceState.bound) {
2423957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                // We have already bound to the service so we don't try to bind again until after we
2433957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                // unbind later on.
2443957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                return;
2453957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
2463957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            if (DEBUG) {
2473957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                Log.i(TAG, "bindServiceAsUser(name=" + name.getClassName() + ", userId=" + userId
2483957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                        + ")");
2493957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
2503957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            Intent i = new Intent(TvInputService.SERVICE_INTERFACE).setComponent(name);
2513957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            mContext.bindServiceAsUser(i, serviceState.connection, Context.BIND_AUTO_CREATE,
2523957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    new UserHandle(userId));
2533957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            serviceState.bound = true;
2543957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        } else if (serviceState.service != null && isStateEmpty) {
2553957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            // This means that the service is already connected but its state indicates that we have
2563957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            // nothing to do with it. Then, disconnect the service.
2573957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            if (DEBUG) {
2583957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                Log.i(TAG, "unbindService(name=" + name.getClassName() + ")");
2593957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
2603957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            mContext.unbindService(serviceState.connection);
2613957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            userState.serviceStateMap.remove(name);
2623957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
2633957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
2643957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
2653957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private void createSessionInternalLocked(ITvInputService service, final IBinder sessionToken,
2667de5e234715a3baa8905afa3dd0c5009af64541fSungsoo Lim            final int userId) {
2677de5e234715a3baa8905afa3dd0c5009af64541fSungsoo Lim        final SessionState sessionState =
2687de5e234715a3baa8905afa3dd0c5009af64541fSungsoo Lim                getUserStateLocked(userId).sessionStateMap.get(sessionToken);
2693957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        if (DEBUG) {
2703957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            Log.d(TAG, "createSessionInternalLocked(name=" + sessionState.name.getClassName()
2713957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    + ")");
2723957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
2733957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        // Set up a callback to send the session token.
2743957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        ITvInputSessionCallback callback = new ITvInputSessionCallback.Stub() {
2753957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            @Override
2763957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            public void onSessionCreated(ITvInputSession session) {
2773957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                if (DEBUG) {
2783957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    Log.d(TAG, "onSessionCreated(name=" + sessionState.name.getClassName() + ")");
2793957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
2803957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                synchronized (mLock) {
2813957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    sessionState.session = session;
282fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang                    if (session == null) {
283fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang                        removeSessionStateLocked(sessionToken, userId);
284fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang                        sendSessionTokenToClientLocked(sessionState.client, sessionState.name, null,
285fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang                                sessionState.seq, userId);
286fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang                    } else {
287fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang                        sendSessionTokenToClientLocked(sessionState.client, sessionState.name,
288fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang                                sessionToken, sessionState.seq, userId);
289fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang                    }
2903957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
2913957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
2923957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        };
2933957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
2943957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        // Create a session. When failed, send a null token immediately.
2953957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        try {
2963957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            service.createSession(callback);
2973957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        } catch (RemoteException e) {
2983957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            Log.e(TAG, "error in createSession", e);
299fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang            removeSessionStateLocked(sessionToken, userId);
3003957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            sendSessionTokenToClientLocked(sessionState.client, sessionState.name, null,
3013957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    sessionState.seq, userId);
3023957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
3033957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
3043957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
3053957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private void sendSessionTokenToClientLocked(ITvInputClient client, ComponentName name,
3063957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            IBinder sessionToken, int seq, int userId) {
3073957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        try {
3083957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            client.onSessionCreated(name, sessionToken, seq);
3093957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        } catch (RemoteException exception) {
3103957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            Log.e(TAG, "error in onSessionCreated", exception);
3113957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
3123957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
3133957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        if (sessionToken == null) {
3143957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            // This means that the session creation failed. We might want to disconnect the service.
3153957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            updateServiceConnectionLocked(name, userId);
3163957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
3173957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
3183957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
319fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang    private void removeSessionStateLocked(IBinder sessionToken, int userId) {
320fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang        // Remove the session state from the global session state map of the current user.
321fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang        UserState userState = getUserStateLocked(userId);
322fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang        SessionState sessionState = userState.sessionStateMap.remove(sessionToken);
323fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang
3247de5e234715a3baa8905afa3dd0c5009af64541fSungsoo Lim        // Also remove the session token from the session token list of the current service.
325fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang        ServiceState serviceState = userState.serviceStateMap.get(sessionState.name);
326fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang        if (serviceState != null) {
3277de5e234715a3baa8905afa3dd0c5009af64541fSungsoo Lim            serviceState.sessionTokens.remove(sessionToken);
328fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang        }
329fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang        updateServiceConnectionLocked(sessionState.name, userId);
330fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang    }
331fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang
3323957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private final class BinderService extends ITvInputManager.Stub {
3333957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        @Override
3343957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        public List<TvInputInfo> getTvInputList(int userId) {
3353957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(),
3363957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    Binder.getCallingUid(), userId, "getTvInputList");
3373957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final long identity = Binder.clearCallingIdentity();
3383957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            try {
3393957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                synchronized (mLock) {
3403957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    UserState userState = getUserStateLocked(resolvedUserId);
3413957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    return new ArrayList<TvInputInfo>(userState.inputList);
3423957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
3433957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            } finally {
3443957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                Binder.restoreCallingIdentity(identity);
3453957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
3463957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
3473957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
3483957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        @Override
3493957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        public boolean getAvailability(final ITvInputClient client, final ComponentName name,
3503957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                int userId) {
3513957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(),
3523957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    Binder.getCallingUid(), userId, "getAvailability");
3533957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final long identity = Binder.clearCallingIdentity();
3543957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            try {
3553957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                synchronized (mLock) {
3563957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    UserState userState = getUserStateLocked(resolvedUserId);
3573957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    ServiceState serviceState = userState.serviceStateMap.get(name);
3583957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    if (serviceState != null) {
3593957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                        // We already know the status of this input service. Return the cached
3603957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                        // status.
3613957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                        return serviceState.available;
3623957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    }
3633957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
3643957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            } finally {
3653957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                Binder.restoreCallingIdentity(identity);
3663957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
3673957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            return false;
3683957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
3693957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
3703957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        @Override
3713957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        public void registerCallback(final ITvInputClient client, final ComponentName name,
3723957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                int userId) {
3733957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(),
3743957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    Binder.getCallingUid(), userId, "registerCallback");
3753957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final long identity = Binder.clearCallingIdentity();
3763957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            try {
3773957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                synchronized (mLock) {
3783957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    // Create a new service callback and add it to the callback map of the current
3793957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    // service.
3803957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    UserState userState = getUserStateLocked(resolvedUserId);
3813957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    ServiceState serviceState = userState.serviceStateMap.get(name);
3823957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    if (serviceState == null) {
3833957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                        serviceState = new ServiceState(name, resolvedUserId);
3843957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                        userState.serviceStateMap.put(name, serviceState);
3853957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    }
3863957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    IBinder iBinder = client.asBinder();
3873957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    if (!serviceState.clients.contains(iBinder)) {
3883957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                        serviceState.clients.add(iBinder);
3893957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    }
3903957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    if (serviceState.service != null) {
3913957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                        if (serviceState.callback != null) {
3923957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                            // We already handled.
3933957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                            return;
3943957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                        }
3953957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                        serviceState.callback = new ServiceCallback(resolvedUserId);
3963957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                        try {
3973957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                            serviceState.service.registerCallback(serviceState.callback);
3983957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                        } catch (RemoteException e) {
3993957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                            Log.e(TAG, "error in registerCallback", e);
4003957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                        }
4013957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    } else {
4023957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                        updateServiceConnectionLocked(name, resolvedUserId);
4033957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    }
4043957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
4053957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            } finally {
4063957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                Binder.restoreCallingIdentity(identity);
4073957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
4083957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
4093957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
4103957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        @Override
4113957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        public void unregisterCallback(ITvInputClient client, ComponentName name, int userId) {
4123957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(),
4133957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    Binder.getCallingUid(), userId, "unregisterCallback");
4143957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final long identity = Binder.clearCallingIdentity();
4153957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            try {
4163957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                synchronized (mLock) {
4173957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    UserState userState = getUserStateLocked(resolvedUserId);
4183957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    ServiceState serviceState = userState.serviceStateMap.get(name);
4193957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    if (serviceState == null) {
4203957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                        return;
4213957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    }
4223957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
4233957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    // Remove this client from the client list and unregister the callback.
4243957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    serviceState.clients.remove(client.asBinder());
4253957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    if (!serviceState.clients.isEmpty()) {
4263957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                        // We have other clients who want to keep the callback. Do this later.
4273957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                        return;
4283957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    }
4293957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    if (serviceState.service == null || serviceState.callback == null) {
4303957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                        return;
4313957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    }
4323957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    try {
4333957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                        serviceState.service.unregisterCallback(serviceState.callback);
4343957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    } catch (RemoteException e) {
4353957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                        Log.e(TAG, "error in unregisterCallback", e);
4363957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    } finally {
4373957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                        serviceState.callback = null;
4383957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                        updateServiceConnectionLocked(name, resolvedUserId);
4393957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    }
4403957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
4413957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            } finally {
4423957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                Binder.restoreCallingIdentity(identity);
4433957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
4443957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
4453957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
4463957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        @Override
4473957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        public void createSession(final ITvInputClient client, final ComponentName name,
4483957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                int seq, int userId) {
4493957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final int callingUid = Binder.getCallingUid();
4503957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
4513957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    userId, "createSession");
4523957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final long identity = Binder.clearCallingIdentity();
4533957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            try {
4543957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                synchronized (mLock) {
4553957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    // Create a new session token and a session state.
4563957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    IBinder sessionToken = new Binder();
4573957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    SessionState sessionState = new SessionState(name, client, seq, callingUid);
4583957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    sessionState.session = null;
4593957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
4603957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    // Add them to the global session state map of the current user.
4613957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    UserState userState = getUserStateLocked(resolvedUserId);
4623957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    userState.sessionStateMap.put(sessionToken, sessionState);
4633957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
4643957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    // Also, add them to the session state map of the current service.
4653957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    ServiceState serviceState = userState.serviceStateMap.get(name);
4663957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    if (serviceState == null) {
4673957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                        serviceState = new ServiceState(name, resolvedUserId);
4683957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                        userState.serviceStateMap.put(name, serviceState);
4693957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    }
4707de5e234715a3baa8905afa3dd0c5009af64541fSungsoo Lim                    serviceState.sessionTokens.add(sessionToken);
4713957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
4723957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    if (serviceState.service != null) {
4733957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                        createSessionInternalLocked(serviceState.service, sessionToken,
4747de5e234715a3baa8905afa3dd0c5009af64541fSungsoo Lim                                resolvedUserId);
4753957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    } else {
4763957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                        updateServiceConnectionLocked(name, resolvedUserId);
4773957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    }
4783957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
4793957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            } finally {
4803957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                Binder.restoreCallingIdentity(identity);
4813957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
4823957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
4833957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
4843957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        @Override
4853957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        public void releaseSession(IBinder sessionToken, int userId) {
4863957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final int callingUid = Binder.getCallingUid();
4873957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
4883957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    userId, "releaseSession");
4893957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final long identity = Binder.clearCallingIdentity();
4903957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            try {
4913957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                synchronized (mLock) {
4923957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    // Release the session.
4933957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    try {
4943957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                        getSessionLocked(sessionToken, callingUid, resolvedUserId).release();
4953957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    } catch (RemoteException e) {
4963957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                        Log.e(TAG, "error in release", e);
4973957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    }
4983957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
499fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang                    removeSessionStateLocked(sessionToken, resolvedUserId);
5003957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
5013957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            } finally {
5023957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                Binder.restoreCallingIdentity(identity);
5033957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
5043957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
5053957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
5063957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        @Override
5073957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        public void setSurface(IBinder sessionToken, Surface surface, int userId) {
5083957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final int callingUid = Binder.getCallingUid();
5093957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
5103957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    userId, "setSurface");
5113957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final long identity = Binder.clearCallingIdentity();
5123957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            try {
5133957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                synchronized (mLock) {
5143957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    try {
5153957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                        getSessionLocked(sessionToken, callingUid, resolvedUserId).setSurface(
5163957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                                surface);
5173957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    } catch (RemoteException e) {
5183957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                        Log.e(TAG, "error in setSurface", e);
5193957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    }
5203957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
5213957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            } finally {
5223957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                Binder.restoreCallingIdentity(identity);
5233957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
5243957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
5253957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
5263957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        @Override
5273957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        public void setVolume(IBinder sessionToken, float volume, int userId) {
5283957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final int callingUid = Binder.getCallingUid();
5293957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
5303957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    userId, "setVolume");
5313957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final long identity = Binder.clearCallingIdentity();
5323957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            try {
5333957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                synchronized (mLock) {
5343957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    try {
5353957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                        getSessionLocked(sessionToken, callingUid, resolvedUserId).setVolume(
5363957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                                volume);
5373957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    } catch (RemoteException e) {
5383957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                        Log.e(TAG, "error in setVolume", e);
5393957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    }
5403957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
5413957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            } finally {
5423957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                Binder.restoreCallingIdentity(identity);
5433957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
5443957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
5453957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
5463957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        @Override
5473957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        public void tune(IBinder sessionToken, final Uri channelUri, int userId) {
5483957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final int callingUid = Binder.getCallingUid();
5493957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
5503957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    userId, "tune");
5513957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final long identity = Binder.clearCallingIdentity();
5523957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            try {
5533957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                synchronized (mLock) {
5543957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    SessionState sessionState = getUserStateLocked(resolvedUserId)
5553957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                            .sessionStateMap.get(sessionToken);
5563957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    final String serviceName = sessionState.name.getClassName();
5573957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    try {
5583957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                        getSessionLocked(sessionToken, callingUid, resolvedUserId).tune(channelUri);
5593957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    } catch (RemoteException e) {
5603957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                        Log.e(TAG, "error in tune", e);
5613957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                        return;
5623957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    }
5633957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
5643957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            } finally {
5653957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                Binder.restoreCallingIdentity(identity);
5663957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
5673957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
5683957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
5693957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
5703957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private static final class UserState {
5713957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        // A list of all known TV inputs on the system.
5723957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        private final List<TvInputInfo> inputList = new ArrayList<TvInputInfo>();
5733957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
5743957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        // A mapping from the name of a TV input service to its state.
5753957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        private final Map<ComponentName, ServiceState> serviceStateMap =
5763957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                new HashMap<ComponentName, ServiceState>();
5773957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
5783957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        // A mapping from the token of a TV input session to its state.
5793957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        private final Map<IBinder, SessionState> sessionStateMap =
5803957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                new HashMap<IBinder, SessionState>();
5813957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
5823957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
5833957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private final class ServiceState {
5843957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        private final List<IBinder> clients = new ArrayList<IBinder>();
5857de5e234715a3baa8905afa3dd0c5009af64541fSungsoo Lim        private final List<IBinder> sessionTokens = new ArrayList<IBinder>();
5863957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        private final ServiceConnection connection;
5873957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
5883957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        private ITvInputService service;
5893957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        private ServiceCallback callback;
5903957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        private boolean bound;
5913957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        private boolean available;
5923957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
5933957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        private ServiceState(ComponentName name, int userId) {
5943957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            this.connection = new InputServiceConnection(userId);
5953957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
5963957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
5973957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
5983957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private static final class SessionState {
5993957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        private final ComponentName name;
6003957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        private final ITvInputClient client;
6013957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        private final int seq;
6023957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        private final int callingUid;
6033957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
6043957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        private ITvInputSession session;
6053957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
6063957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        private SessionState(ComponentName name, ITvInputClient client, int seq, int callingUid) {
6073957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            this.name = name;
6083957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            this.client = client;
6093957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            this.seq = seq;
6103957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            this.callingUid = callingUid;
6113957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
6123957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
6133957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
6143957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private final class InputServiceConnection implements ServiceConnection {
6153957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        private final int mUserId;
6163957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
6173957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        private InputServiceConnection(int userId) {
6183957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            mUserId = userId;
6193957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
6203957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
6213957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        @Override
6223957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        public void onServiceConnected(ComponentName name, IBinder service) {
6233957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            if (DEBUG) {
6243957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                Log.d(TAG, "onServiceConnected(name=" + name.getClassName() + ")");
6253957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
6263957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            synchronized (mLock) {
6273957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                ServiceState serviceState = getServiceStateLocked(name, mUserId);
6283957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                serviceState.service = ITvInputService.Stub.asInterface(service);
6293957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
6303957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                // Register a callback, if we need to.
6313957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                if (!serviceState.clients.isEmpty() && serviceState.callback == null) {
6323957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    serviceState.callback = new ServiceCallback(mUserId);
6333957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    try {
6343957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                        serviceState.service.registerCallback(serviceState.callback);
6353957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    } catch (RemoteException e) {
6363957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                        Log.e(TAG, "error in registerCallback", e);
6373957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    }
6383957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
6393957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
6403957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                // And create sessions, if any.
6417de5e234715a3baa8905afa3dd0c5009af64541fSungsoo Lim                for (IBinder sessionToken : serviceState.sessionTokens) {
6427de5e234715a3baa8905afa3dd0c5009af64541fSungsoo Lim                    createSessionInternalLocked(serviceState.service, sessionToken, mUserId);
6433957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
6443957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
6453957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
6463957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
6473957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        @Override
6483957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        public void onServiceDisconnected(ComponentName name) {
6493957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            if (DEBUG) {
6503957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                Log.d(TAG, "onServiceDisconnected(name=" + name.getClassName() + ")");
6513957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
6523957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
6533957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
6543957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
6553957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private final class ServiceCallback extends ITvInputServiceCallback.Stub {
6563957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        private final int mUserId;
6573957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
6583957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        ServiceCallback(int userId) {
6593957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            mUserId = userId;
6603957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
6613957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
6623957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        @Override
6633957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        public void onAvailabilityChanged(ComponentName name, boolean isAvailable)
6643957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                throws RemoteException {
6653957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            if (DEBUG) {
6663957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                Log.d(TAG, "onAvailabilityChanged(name=" + name.getClassName() + ", isAvailable="
6673957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                        + isAvailable + ")");
6683957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
6693957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            synchronized (mLock) {
6703957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                ServiceState serviceState = getServiceStateLocked(name, mUserId);
6713957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                serviceState.available = isAvailable;
6723957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                for (IBinder iBinder : serviceState.clients) {
6733957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    ITvInputClient client = ITvInputClient.Stub.asInterface(iBinder);
6743957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    client.onAvailabilityChanged(name, isAvailable);
6753957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
6763957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
6773957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
6783957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
6793957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo}
680