1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.tv; 18 19 import android.content.Context; 20 import android.os.Handler; 21 import android.os.IBinder; 22 import android.os.Looper; 23 import android.os.Message; 24 import android.util.ArrayMap; 25 import android.util.Slog; 26 27 import com.android.server.SystemService; 28 import com.android.server.Watchdog; 29 30 import java.io.IOException; 31 import java.util.ArrayList; 32 import java.util.Map; 33 34 /** 35 * TvRemoteService represents a system service that allows a connected 36 * remote control (emote) service to inject white-listed input events 37 * and call other specified methods for functioning as an emote service. 38 * <p/> 39 * This service is intended for use only by white-listed packages. 40 */ 41 public class TvRemoteService extends SystemService implements Watchdog.Monitor { 42 private static final String TAG = "TvRemoteService"; 43 private static final boolean DEBUG = false; 44 private static final boolean DEBUG_KEYS = false; 45 46 private Map<IBinder, UinputBridge> mBridgeMap = new ArrayMap(); 47 private Map<IBinder, TvRemoteProviderProxy> mProviderMap = new ArrayMap(); 48 private ArrayList<TvRemoteProviderProxy> mProviderList = new ArrayList<>(); 49 50 /** 51 * State guarded by mLock. 52 * This is the second lock in sequence for an incoming call. 53 * The first lock is always {@link TvRemoteProviderProxy#mLock} 54 * 55 * There are currently no methods that break this sequence. 56 * Special note: 57 * Outgoing call informInputBridgeConnected(), which is called from 58 * openInputBridgeInternalLocked() uses a handler thereby relinquishing held locks. 59 */ 60 private final Object mLock = new Object(); 61 62 public final UserHandler mHandler; 63 64 public TvRemoteService(Context context) { 65 super(context); 66 mHandler = new UserHandler(new UserProvider(TvRemoteService.this), context); 67 Watchdog.getInstance().addMonitor(this); 68 } 69 70 @Override 71 public void onStart() { 72 if (DEBUG) Slog.d(TAG, "onStart()"); 73 } 74 75 @Override 76 public void monitor() { 77 synchronized (mLock) { /* check for deadlock */ } 78 } 79 80 @Override 81 public void onBootPhase(int phase) { 82 if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) { 83 if (DEBUG) Slog.d(TAG, "PHASE_THIRD_PARTY_APPS_CAN_START"); 84 mHandler.sendEmptyMessage(UserHandler.MSG_START); 85 } 86 } 87 88 //Outgoing calls. 89 private void informInputBridgeConnected(IBinder token) { 90 mHandler.obtainMessage(UserHandler.MSG_INPUT_BRIDGE_CONNECTED, 0, 0, token).sendToTarget(); 91 } 92 93 // Incoming calls. 94 private void openInputBridgeInternalLocked(TvRemoteProviderProxy provider, IBinder token, 95 String name, int width, int height, 96 int maxPointers) { 97 if (DEBUG) { 98 Slog.d(TAG, "openInputBridgeInternalLocked(), token: " + token + ", name: " + name + 99 ", width: " + width + ", height: " + height + ", maxPointers: " + maxPointers); 100 } 101 102 try { 103 //Create a new bridge, if one does not exist already 104 if (mBridgeMap.containsKey(token)) { 105 if (DEBUG) Slog.d(TAG, "RemoteBridge already exists"); 106 // Respond back with success. 107 informInputBridgeConnected(token); 108 return; 109 } 110 111 UinputBridge inputBridge = new UinputBridge(token, name, width, height, maxPointers); 112 113 mBridgeMap.put(token, inputBridge); 114 mProviderMap.put(token, provider); 115 116 // Respond back with success. 117 informInputBridgeConnected(token); 118 119 } catch (IOException ioe) { 120 Slog.e(TAG, "Cannot create device for " + name); 121 } 122 } 123 124 private void closeInputBridgeInternalLocked(IBinder token) { 125 if (DEBUG) { 126 Slog.d(TAG, "closeInputBridgeInternalLocked(), token: " + token); 127 } 128 129 // Close an existing RemoteBridge 130 UinputBridge inputBridge = mBridgeMap.get(token); 131 if (inputBridge != null) { 132 inputBridge.close(token); 133 } 134 135 mBridgeMap.remove(token); 136 } 137 138 139 private void clearInputBridgeInternalLocked(IBinder token) { 140 if (DEBUG) { 141 Slog.d(TAG, "clearInputBridgeInternalLocked(), token: " + token); 142 } 143 144 UinputBridge inputBridge = mBridgeMap.get(token); 145 if (inputBridge != null) { 146 inputBridge.clear(token); 147 } 148 } 149 150 private void sendTimeStampInternalLocked(IBinder token, long timestamp) { 151 UinputBridge inputBridge = mBridgeMap.get(token); 152 if (inputBridge != null) { 153 inputBridge.sendTimestamp(token, timestamp); 154 } 155 } 156 157 private void sendKeyDownInternalLocked(IBinder token, int keyCode) { 158 if (DEBUG_KEYS) { 159 Slog.d(TAG, "sendKeyDownInternalLocked(), token: " + token + ", keyCode: " + keyCode); 160 } 161 162 UinputBridge inputBridge = mBridgeMap.get(token); 163 if (inputBridge != null) { 164 inputBridge.sendKeyDown(token, keyCode); 165 } 166 } 167 168 private void sendKeyUpInternalLocked(IBinder token, int keyCode) { 169 if (DEBUG_KEYS) { 170 Slog.d(TAG, "sendKeyUpInternalLocked(), token: " + token + ", keyCode: " + keyCode); 171 } 172 173 UinputBridge inputBridge = mBridgeMap.get(token); 174 if (inputBridge != null) { 175 inputBridge.sendKeyUp(token, keyCode); 176 } 177 } 178 179 private void sendPointerDownInternalLocked(IBinder token, int pointerId, int x, int y) { 180 if (DEBUG_KEYS) { 181 Slog.d(TAG, "sendPointerDownInternalLocked(), token: " + token + ", pointerId: " + 182 pointerId + ", x: " + x + ", y: " + y); 183 } 184 185 UinputBridge inputBridge = mBridgeMap.get(token); 186 if (inputBridge != null) { 187 inputBridge.sendPointerDown(token, pointerId, x, y); 188 } 189 } 190 191 private void sendPointerUpInternalLocked(IBinder token, int pointerId) { 192 if (DEBUG_KEYS) { 193 Slog.d(TAG, "sendPointerUpInternalLocked(), token: " + token + ", pointerId: " + 194 pointerId); 195 } 196 197 UinputBridge inputBridge = mBridgeMap.get(token); 198 if (inputBridge != null) { 199 inputBridge.sendPointerUp(token, pointerId); 200 } 201 } 202 203 private void sendPointerSyncInternalLocked(IBinder token) { 204 if (DEBUG_KEYS) { 205 Slog.d(TAG, "sendPointerSyncInternalLocked(), token: " + token); 206 } 207 208 UinputBridge inputBridge = mBridgeMap.get(token); 209 if (inputBridge != null) { 210 inputBridge.sendPointerSync(token); 211 } 212 } 213 214 private final class UserHandler extends Handler { 215 216 public static final int MSG_START = 1; 217 public static final int MSG_INPUT_BRIDGE_CONNECTED = 2; 218 219 private final TvRemoteProviderWatcher mWatcher; 220 private boolean mRunning; 221 222 public UserHandler(UserProvider provider, Context context) { 223 super(Looper.getMainLooper(), null, true); 224 mWatcher = new TvRemoteProviderWatcher(context, provider, this); 225 } 226 227 @Override 228 public void handleMessage(Message msg) { 229 switch (msg.what) { 230 case MSG_START: { 231 start(); 232 break; 233 } 234 case MSG_INPUT_BRIDGE_CONNECTED: { 235 IBinder token = (IBinder) msg.obj; 236 TvRemoteProviderProxy provider = mProviderMap.get(token); 237 if (provider != null) { 238 provider.inputBridgeConnected(token); 239 } 240 break; 241 } 242 } 243 } 244 245 private void start() { 246 if (!mRunning) { 247 mRunning = true; 248 mWatcher.start(); // also starts all providers 249 } 250 } 251 } 252 253 private final class UserProvider implements TvRemoteProviderWatcher.ProviderMethods, 254 TvRemoteProviderProxy.ProviderMethods { 255 256 private final TvRemoteService mService; 257 258 public UserProvider(TvRemoteService service) { 259 mService = service; 260 } 261 262 @Override 263 public void openInputBridge(TvRemoteProviderProxy provider, IBinder token, String name, 264 int width, int height, int maxPointers) { 265 if (DEBUG) { 266 Slog.d(TAG, "openInputBridge(), token: " + token + 267 ", name: " + name + ", width: " + width + 268 ", height: " + height + ", maxPointers: " + maxPointers); 269 } 270 271 synchronized (mLock) { 272 if (mProviderList.contains(provider)) { 273 mService.openInputBridgeInternalLocked(provider, token, name, width, height, 274 maxPointers); 275 } 276 } 277 } 278 279 @Override 280 public void closeInputBridge(TvRemoteProviderProxy provider, IBinder token) { 281 if (DEBUG) Slog.d(TAG, "closeInputBridge(), token: " + token); 282 synchronized (mLock) { 283 if (mProviderList.contains(provider)) { 284 mService.closeInputBridgeInternalLocked(token); 285 mProviderMap.remove(token); 286 } 287 } 288 } 289 290 @Override 291 public void clearInputBridge(TvRemoteProviderProxy provider, IBinder token) { 292 if (DEBUG) Slog.d(TAG, "clearInputBridge(), token: " + token); 293 synchronized (mLock) { 294 if (mProviderList.contains(provider)) { 295 mService.clearInputBridgeInternalLocked(token); 296 } 297 } 298 } 299 300 @Override 301 public void sendTimeStamp(TvRemoteProviderProxy provider, IBinder token, long timestamp) { 302 synchronized (mLock) { 303 if (mProviderList.contains(provider)) { 304 mService.sendTimeStampInternalLocked(token, timestamp); 305 } 306 } 307 } 308 309 @Override 310 public void sendKeyDown(TvRemoteProviderProxy provider, IBinder token, int keyCode) { 311 if (DEBUG_KEYS) { 312 Slog.d(TAG, "sendKeyDown(), token: " + token + ", keyCode: " + keyCode); 313 } 314 synchronized (mLock) { 315 if (mProviderList.contains(provider)) { 316 mService.sendKeyDownInternalLocked(token, keyCode); 317 } 318 } 319 } 320 321 @Override 322 public void sendKeyUp(TvRemoteProviderProxy provider, IBinder token, int keyCode) { 323 if (DEBUG_KEYS) { 324 Slog.d(TAG, "sendKeyUp(), token: " + token + ", keyCode: " + keyCode); 325 } 326 synchronized (mLock) { 327 if (mProviderList.contains(provider)) { 328 mService.sendKeyUpInternalLocked(token, keyCode); 329 } 330 } 331 } 332 333 @Override 334 public void sendPointerDown(TvRemoteProviderProxy provider, IBinder token, int pointerId, 335 int x, int y) { 336 if (DEBUG_KEYS) { 337 Slog.d(TAG, "sendPointerDown(), token: " + token + ", pointerId: " + pointerId); 338 } 339 synchronized (mLock) { 340 if (mProviderList.contains(provider)) { 341 mService.sendPointerDownInternalLocked(token, pointerId, x, y); 342 } 343 } 344 } 345 346 @Override 347 public void sendPointerUp(TvRemoteProviderProxy provider, IBinder token, int pointerId) { 348 if (DEBUG_KEYS) { 349 Slog.d(TAG, "sendPointerUp(), token: " + token + ", pointerId: " + pointerId); 350 } 351 synchronized (mLock) { 352 if (mProviderList.contains(provider)) { 353 mService.sendPointerUpInternalLocked(token, pointerId); 354 } 355 } 356 } 357 358 @Override 359 public void sendPointerSync(TvRemoteProviderProxy provider, IBinder token) { 360 if (DEBUG_KEYS) Slog.d(TAG, "sendPointerSync(), token: " + token); 361 synchronized (mLock) { 362 if (mProviderList.contains(provider)) { 363 mService.sendPointerSyncInternalLocked(token); 364 } 365 } 366 } 367 368 @Override 369 public void addProvider(TvRemoteProviderProxy provider) { 370 if (DEBUG) Slog.d(TAG, "addProvider " + provider); 371 synchronized (mLock) { 372 provider.setProviderSink(this); 373 mProviderList.add(provider); 374 Slog.d(TAG, "provider: " + provider.toString()); 375 } 376 } 377 378 @Override 379 public void removeProvider(TvRemoteProviderProxy provider) { 380 if (DEBUG) Slog.d(TAG, "removeProvider " + provider); 381 synchronized (mLock) { 382 if (mProviderList.remove(provider) == false) { 383 Slog.e(TAG, "Unknown provider " + provider); 384 } 385 } 386 } 387 } 388 } 389