TvInputManagerService.java revision b06cb8870f0407f18bb1225065a93aba2a5de2bf
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) { 2003957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo throw new IllegalStateException("Service state not found for " + name + " (userId=" + 2013957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 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 } 2363957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo boolean isStateEmpty = serviceState.clients.size() == 0 2373957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo && serviceState.sessionStateMap.size() == 0; 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, 2663957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo final SessionState sessionState, final int userId) { 2673957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo if (DEBUG) { 2683957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo Log.d(TAG, "createSessionInternalLocked(name=" + sessionState.name.getClassName() 2693957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo + ")"); 2703957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 2713957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo // Set up a callback to send the session token. 2723957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo ITvInputSessionCallback callback = new ITvInputSessionCallback.Stub() { 2733957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo @Override 2743957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo public void onSessionCreated(ITvInputSession session) { 2753957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo if (DEBUG) { 2763957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo Log.d(TAG, "onSessionCreated(name=" + sessionState.name.getClassName() + ")"); 2773957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 2783957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo synchronized (mLock) { 2793957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo sessionState.session = session; 2803957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo sendSessionTokenToClientLocked(sessionState.client, sessionState.name, 2813957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo sessionToken, sessionState.seq, userId); 2823957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 2833957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 2843957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo }; 2853957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 2863957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo // Create a session. When failed, send a null token immediately. 2873957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo try { 2883957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo service.createSession(callback); 2893957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } catch (RemoteException e) { 2903957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo Log.e(TAG, "error in createSession", e); 2913957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo sendSessionTokenToClientLocked(sessionState.client, sessionState.name, null, 2923957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo sessionState.seq, userId); 2933957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 2943957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 2953957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 2963957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo private void sendSessionTokenToClientLocked(ITvInputClient client, ComponentName name, 2973957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo IBinder sessionToken, int seq, int userId) { 2983957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo try { 2993957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo client.onSessionCreated(name, sessionToken, seq); 3003957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } catch (RemoteException exception) { 3013957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo Log.e(TAG, "error in onSessionCreated", exception); 3023957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 3033957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 3043957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo if (sessionToken == null) { 3053957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo // This means that the session creation failed. We might want to disconnect the service. 3063957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo updateServiceConnectionLocked(name, userId); 3073957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 3083957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 3093957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 3103957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo private final class BinderService extends ITvInputManager.Stub { 3113957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo @Override 3123957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo public List<TvInputInfo> getTvInputList(int userId) { 3133957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), 3143957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo Binder.getCallingUid(), userId, "getTvInputList"); 3153957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo final long identity = Binder.clearCallingIdentity(); 3163957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo try { 3173957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo synchronized (mLock) { 3183957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo UserState userState = getUserStateLocked(resolvedUserId); 3193957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo return new ArrayList<TvInputInfo>(userState.inputList); 3203957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 3213957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } finally { 3223957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo Binder.restoreCallingIdentity(identity); 3233957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 3243957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 3253957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 3263957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo @Override 3273957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo public boolean getAvailability(final ITvInputClient client, final ComponentName name, 3283957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo int userId) { 3293957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), 3303957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo Binder.getCallingUid(), userId, "getAvailability"); 3313957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo final long identity = Binder.clearCallingIdentity(); 3323957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo try { 3333957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo synchronized (mLock) { 3343957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo UserState userState = getUserStateLocked(resolvedUserId); 3353957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo ServiceState serviceState = userState.serviceStateMap.get(name); 3363957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo if (serviceState != null) { 3373957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo // We already know the status of this input service. Return the cached 3383957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo // status. 3393957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo return serviceState.available; 3403957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 3413957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 3423957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } finally { 3433957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo Binder.restoreCallingIdentity(identity); 3443957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 3453957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo return false; 3463957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 3473957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 3483957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo @Override 3493957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo public void registerCallback(final ITvInputClient client, final ComponentName name, 3503957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo int userId) { 3513957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), 3523957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo Binder.getCallingUid(), userId, "registerCallback"); 3533957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo final long identity = Binder.clearCallingIdentity(); 3543957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo try { 3553957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo synchronized (mLock) { 3563957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo // Create a new service callback and add it to the callback map of the current 3573957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo // service. 3583957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo UserState userState = getUserStateLocked(resolvedUserId); 3593957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo ServiceState serviceState = userState.serviceStateMap.get(name); 3603957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo if (serviceState == null) { 3613957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo serviceState = new ServiceState(name, resolvedUserId); 3623957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo userState.serviceStateMap.put(name, serviceState); 3633957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 3643957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo IBinder iBinder = client.asBinder(); 3653957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo if (!serviceState.clients.contains(iBinder)) { 3663957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo serviceState.clients.add(iBinder); 3673957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 3683957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo if (serviceState.service != null) { 3693957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo if (serviceState.callback != null) { 3703957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo // We already handled. 3713957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo return; 3723957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 3733957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo serviceState.callback = new ServiceCallback(resolvedUserId); 3743957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo try { 3753957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo serviceState.service.registerCallback(serviceState.callback); 3763957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } catch (RemoteException e) { 3773957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo Log.e(TAG, "error in registerCallback", e); 3783957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 3793957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } else { 3803957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo updateServiceConnectionLocked(name, resolvedUserId); 3813957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 3823957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 3833957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } finally { 3843957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo Binder.restoreCallingIdentity(identity); 3853957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 3863957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 3873957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 3883957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo @Override 3893957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo public void unregisterCallback(ITvInputClient client, ComponentName name, int userId) { 3903957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), 3913957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo Binder.getCallingUid(), userId, "unregisterCallback"); 3923957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo final long identity = Binder.clearCallingIdentity(); 3933957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo try { 3943957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo synchronized (mLock) { 3953957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo UserState userState = getUserStateLocked(resolvedUserId); 3963957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo ServiceState serviceState = userState.serviceStateMap.get(name); 3973957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo if (serviceState == null) { 3983957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo return; 3993957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 4003957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 4013957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo // Remove this client from the client list and unregister the callback. 4023957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo serviceState.clients.remove(client.asBinder()); 4033957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo if (!serviceState.clients.isEmpty()) { 4043957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo // We have other clients who want to keep the callback. Do this later. 4053957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo return; 4063957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 4073957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo if (serviceState.service == null || serviceState.callback == null) { 4083957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo return; 4093957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 4103957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo try { 4113957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo serviceState.service.unregisterCallback(serviceState.callback); 4123957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } catch (RemoteException e) { 4133957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo Log.e(TAG, "error in unregisterCallback", e); 4143957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } finally { 4153957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo serviceState.callback = null; 4163957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo updateServiceConnectionLocked(name, resolvedUserId); 4173957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 4183957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 4193957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } finally { 4203957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo Binder.restoreCallingIdentity(identity); 4213957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 4223957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 4233957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 4243957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo @Override 4253957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo public void createSession(final ITvInputClient client, final ComponentName name, 4263957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo int seq, int userId) { 4273957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo final int callingUid = Binder.getCallingUid(); 4283957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid, 4293957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo userId, "createSession"); 4303957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo final long identity = Binder.clearCallingIdentity(); 4313957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo try { 4323957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo synchronized (mLock) { 4333957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo // Create a new session token and a session state. 4343957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo IBinder sessionToken = new Binder(); 4353957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo SessionState sessionState = new SessionState(name, client, seq, callingUid); 4363957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo sessionState.session = null; 4373957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 4383957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo // Add them to the global session state map of the current user. 4393957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo UserState userState = getUserStateLocked(resolvedUserId); 4403957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo userState.sessionStateMap.put(sessionToken, sessionState); 4413957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 4423957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo // Also, add them to the session state map of the current service. 4433957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo ServiceState serviceState = userState.serviceStateMap.get(name); 4443957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo if (serviceState == null) { 4453957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo serviceState = new ServiceState(name, resolvedUserId); 4463957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo userState.serviceStateMap.put(name, serviceState); 4473957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 4483957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo serviceState.sessionStateMap.put(sessionToken, sessionState); 4493957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 4503957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo if (serviceState.service != null) { 4513957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo createSessionInternalLocked(serviceState.service, sessionToken, 4523957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo sessionState, resolvedUserId); 4533957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } else { 4543957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo updateServiceConnectionLocked(name, resolvedUserId); 4553957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 4563957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 4573957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } finally { 4583957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo Binder.restoreCallingIdentity(identity); 4593957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 4603957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 4613957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 4623957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo @Override 4633957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo public void releaseSession(IBinder sessionToken, int userId) { 4643957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo final int callingUid = Binder.getCallingUid(); 4653957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid, 4663957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo userId, "releaseSession"); 4673957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo final long identity = Binder.clearCallingIdentity(); 4683957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo try { 4693957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo synchronized (mLock) { 4703957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo // Release the session. 4713957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo try { 4723957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo getSessionLocked(sessionToken, callingUid, resolvedUserId).release(); 4733957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } catch (RemoteException e) { 4743957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo Log.e(TAG, "error in release", e); 4753957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 4763957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 4773957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo // Remove its state from the global session state map of the current user. 4783957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo UserState userState = getUserStateLocked(resolvedUserId); 4793957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo SessionState sessionState = userState.sessionStateMap.remove(sessionToken); 4803957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 4813957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo // Also remove it from the session state map of the current service. 4823957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo ServiceState serviceState = userState.serviceStateMap.get(sessionState.name); 4833957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo if (serviceState != null) { 4843957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo serviceState.sessionStateMap.remove(sessionToken); 4853957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 4863957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 4873957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo updateServiceConnectionLocked(sessionState.name, resolvedUserId); 4883957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 4893957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } finally { 4903957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo Binder.restoreCallingIdentity(identity); 4913957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 4923957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 4933957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 4943957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo @Override 4953957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo public void setSurface(IBinder sessionToken, Surface surface, int userId) { 4963957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo final int callingUid = Binder.getCallingUid(); 4973957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid, 4983957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo userId, "setSurface"); 4993957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo final long identity = Binder.clearCallingIdentity(); 5003957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo try { 5013957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo synchronized (mLock) { 5023957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo try { 5033957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo getSessionLocked(sessionToken, callingUid, resolvedUserId).setSurface( 5043957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo surface); 5053957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } catch (RemoteException e) { 5063957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo Log.e(TAG, "error in setSurface", e); 5073957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 5083957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 5093957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } finally { 5103957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo Binder.restoreCallingIdentity(identity); 5113957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 5123957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 5133957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 5143957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo @Override 5153957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo public void setVolume(IBinder sessionToken, float volume, int userId) { 5163957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo final int callingUid = Binder.getCallingUid(); 5173957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid, 5183957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo userId, "setVolume"); 5193957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo final long identity = Binder.clearCallingIdentity(); 5203957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo try { 5213957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo synchronized (mLock) { 5223957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo try { 5233957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo getSessionLocked(sessionToken, callingUid, resolvedUserId).setVolume( 5243957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo volume); 5253957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } catch (RemoteException e) { 5263957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo Log.e(TAG, "error in setVolume", e); 5273957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 5283957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 5293957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } finally { 5303957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo Binder.restoreCallingIdentity(identity); 5313957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 5323957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 5333957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 5343957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo @Override 5353957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo public void tune(IBinder sessionToken, final Uri channelUri, int userId) { 5363957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo final int callingUid = Binder.getCallingUid(); 5373957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid, 5383957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo userId, "tune"); 5393957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo final long identity = Binder.clearCallingIdentity(); 5403957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo try { 5413957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo synchronized (mLock) { 5423957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo SessionState sessionState = getUserStateLocked(resolvedUserId) 5433957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo .sessionStateMap.get(sessionToken); 5443957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo final String serviceName = sessionState.name.getClassName(); 5453957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo try { 5463957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo getSessionLocked(sessionToken, callingUid, resolvedUserId).tune(channelUri); 5473957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } catch (RemoteException e) { 5483957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo Log.e(TAG, "error in tune", e); 5493957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo return; 5503957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 5513957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 5523957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } finally { 5533957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo Binder.restoreCallingIdentity(identity); 5543957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 5553957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 5563957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 5573957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 5583957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo private static final class UserState { 5593957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo // A list of all known TV inputs on the system. 5603957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo private final List<TvInputInfo> inputList = new ArrayList<TvInputInfo>(); 5613957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 5623957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo // A mapping from the name of a TV input service to its state. 5633957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo private final Map<ComponentName, ServiceState> serviceStateMap = 5643957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo new HashMap<ComponentName, ServiceState>(); 5653957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 5663957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo // A mapping from the token of a TV input session to its state. 5673957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo private final Map<IBinder, SessionState> sessionStateMap = 5683957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo new HashMap<IBinder, SessionState>(); 5693957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 5703957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 5713957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo private final class ServiceState { 5723957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo private final List<IBinder> clients = new ArrayList<IBinder>(); 5733957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo private final ArrayMap<IBinder, SessionState> sessionStateMap = new ArrayMap<IBinder, 5743957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo SessionState>(); 5753957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo private final ServiceConnection connection; 5763957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 5773957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo private ITvInputService service; 5783957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo private ServiceCallback callback; 5793957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo private boolean bound; 5803957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo private boolean available; 5813957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 5823957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo private ServiceState(ComponentName name, int userId) { 5833957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo this.connection = new InputServiceConnection(userId); 5843957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 5853957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 5863957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 5873957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo private static final class SessionState { 5883957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo private final ComponentName name; 5893957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo private final ITvInputClient client; 5903957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo private final int seq; 5913957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo private final int callingUid; 5923957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 5933957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo private ITvInputSession session; 5943957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 5953957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo private SessionState(ComponentName name, ITvInputClient client, int seq, int callingUid) { 5963957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo this.name = name; 5973957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo this.client = client; 5983957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo this.seq = seq; 5993957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo this.callingUid = callingUid; 6003957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 6013957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 6023957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 6033957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo private final class InputServiceConnection implements ServiceConnection { 6043957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo private final int mUserId; 6053957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 6063957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo private InputServiceConnection(int userId) { 6073957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo mUserId = userId; 6083957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 6093957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 6103957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo @Override 6113957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo public void onServiceConnected(ComponentName name, IBinder service) { 6123957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo if (DEBUG) { 6133957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo Log.d(TAG, "onServiceConnected(name=" + name.getClassName() + ")"); 6143957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 6153957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo synchronized (mLock) { 6163957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo ServiceState serviceState = getServiceStateLocked(name, mUserId); 6173957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo serviceState.service = ITvInputService.Stub.asInterface(service); 6183957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 6193957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo // Register a callback, if we need to. 6203957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo if (!serviceState.clients.isEmpty() && serviceState.callback == null) { 6213957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo serviceState.callback = new ServiceCallback(mUserId); 6223957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo try { 6233957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo serviceState.service.registerCallback(serviceState.callback); 6243957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } catch (RemoteException e) { 6253957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo Log.e(TAG, "error in registerCallback", e); 6263957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 6273957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 6283957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 6293957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo // And create sessions, if any. 6303957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo for (Map.Entry<IBinder, SessionState> entry : serviceState.sessionStateMap 6313957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo .entrySet()) { 6323957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo createSessionInternalLocked(serviceState.service, entry.getKey(), 6333957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo entry.getValue(), mUserId); 6343957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 6353957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 6363957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 6373957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 6383957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo @Override 6393957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo public void onServiceDisconnected(ComponentName name) { 6403957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo if (DEBUG) { 6413957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo Log.d(TAG, "onServiceDisconnected(name=" + name.getClassName() + ")"); 6423957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 6433957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 6443957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 6453957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 6463957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo private final class ServiceCallback extends ITvInputServiceCallback.Stub { 6473957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo private final int mUserId; 6483957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 6493957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo ServiceCallback(int userId) { 6503957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo mUserId = userId; 6513957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 6523957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 6533957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo @Override 6543957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo public void onAvailabilityChanged(ComponentName name, boolean isAvailable) 6553957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo throws RemoteException { 6563957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo if (DEBUG) { 6573957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo Log.d(TAG, "onAvailabilityChanged(name=" + name.getClassName() + ", isAvailable=" 6583957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo + isAvailable + ")"); 6593957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 6603957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo synchronized (mLock) { 6613957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo ServiceState serviceState = getServiceStateLocked(name, mUserId); 6623957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo serviceState.available = isAvailable; 6633957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo for (IBinder iBinder : serviceState.clients) { 6643957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo ITvInputClient client = ITvInputClient.Stub.asInterface(iBinder); 6653957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo client.onAvailabilityChanged(name, isAvailable); 6663957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 6673957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 6683957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 6693957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 6703957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo} 671