1 /* 2 * Copyright 2020 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 android.media.tv.tunerresourcemanager; 18 19 import android.annotation.CallbackExecutor; 20 import android.annotation.IntDef; 21 import android.annotation.NonNull; 22 import android.annotation.Nullable; 23 import android.annotation.RequiresFeature; 24 import android.annotation.SystemService; 25 import android.content.Context; 26 import android.content.pm.PackageManager; 27 import android.os.Binder; 28 import android.os.RemoteException; 29 import android.util.Log; 30 31 import java.lang.annotation.Retention; 32 import java.lang.annotation.RetentionPolicy; 33 import java.util.concurrent.Executor; 34 35 /** 36 * Interface of the Tuner Resource Manager(TRM). It manages resources used by TV Tuners. 37 * <p>Resources include: 38 * <ul> 39 * <li>TunerFrontend {@link android.media.tv.tuner.frontend}. 40 * <li>TunerLnb {@link android.media.tv.tuner.Lnb}. 41 * <li>MediaCas {@link android.media.MediaCas}. 42 * <ul> 43 * 44 * <p>Expected workflow is: 45 * <ul> 46 * <li>Tuner Java/MediaCas/TIF update resources of the current device with TRM. 47 * <li>Client registers its profile through {@link #registerClientProfile(ResourceClientProfile, 48 * Executor, ResourcesReclaimListener, int[])}. 49 * <li>Client requests resources through request APIs. 50 * <li>If the resource needs to be handed to a higher priority client from a lower priority 51 * one, TRM calls IResourcesReclaimListener registered by the lower priority client to release 52 * the resource. 53 * <ul> 54 * 55 * <p>TRM also exposes its priority comparison algorithm as a helping method to other services. 56 * {@see #isHigherPriority(ResourceClientProfile, ResourceClientProfile)}. 57 * 58 * @hide 59 */ 60 @RequiresFeature(PackageManager.FEATURE_LIVE_TV) 61 @SystemService(Context.TV_TUNER_RESOURCE_MGR_SERVICE) 62 public class TunerResourceManager { 63 private static final String TAG = "TunerResourceManager"; 64 private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); 65 66 public static final int INVALID_RESOURCE_HANDLE = -1; 67 public static final int INVALID_OWNER_ID = -1; 68 /** 69 * Tuner resource type to help generate resource handle 70 */ 71 @IntDef({ 72 TUNER_RESOURCE_TYPE_FRONTEND, 73 TUNER_RESOURCE_TYPE_DEMUX, 74 TUNER_RESOURCE_TYPE_DESCRAMBLER, 75 TUNER_RESOURCE_TYPE_LNB, 76 TUNER_RESOURCE_TYPE_CAS_SESSION, 77 TUNER_RESOURCE_TYPE_MAX, 78 }) 79 @Retention(RetentionPolicy.SOURCE) 80 public @interface TunerResourceType {} 81 82 public static final int TUNER_RESOURCE_TYPE_FRONTEND = 0; 83 public static final int TUNER_RESOURCE_TYPE_DEMUX = 1; 84 public static final int TUNER_RESOURCE_TYPE_DESCRAMBLER = 2; 85 public static final int TUNER_RESOURCE_TYPE_LNB = 3; 86 public static final int TUNER_RESOURCE_TYPE_CAS_SESSION = 4; 87 public static final int TUNER_RESOURCE_TYPE_MAX = 5; 88 89 private final ITunerResourceManager mService; 90 private final int mUserId; 91 92 /** 93 * @hide 94 */ TunerResourceManager(ITunerResourceManager service, int userId)95 public TunerResourceManager(ITunerResourceManager service, int userId) { 96 mService = service; 97 mUserId = userId; 98 } 99 100 /** 101 * This API is used by the client to register their profile with the Tuner Resource manager. 102 * 103 * <p>The profile contains information that can show the base priority score of the client. 104 * 105 * @param profile {@link ResourceClientProfile} profile of the current client. Undefined use 106 * case would cause IllegalArgumentException. 107 * @param executor the executor on which the listener would be invoked. 108 * @param listener {@link ResourcesReclaimListener} callback to reclaim clients' resources when 109 * needed. 110 * @param clientId returned a clientId from the resource manager when the 111 * the client registeres. 112 * @throws IllegalArgumentException when {@code profile} contains undefined use case. 113 */ registerClientProfile(@onNull ResourceClientProfile profile, @NonNull @CallbackExecutor Executor executor, @NonNull ResourcesReclaimListener listener, @NonNull int[] clientId)114 public void registerClientProfile(@NonNull ResourceClientProfile profile, 115 @NonNull @CallbackExecutor Executor executor, 116 @NonNull ResourcesReclaimListener listener, 117 @NonNull int[] clientId) { 118 // TODO: throw new IllegalArgumentException("Unknown client use case") 119 // when the use case is not defined. 120 try { 121 mService.registerClientProfile(profile, 122 new IResourcesReclaimListener.Stub() { 123 @Override 124 public void onReclaimResources() { 125 final long identity = Binder.clearCallingIdentity(); 126 try { 127 executor.execute(() -> listener.onReclaimResources()); 128 } finally { 129 Binder.restoreCallingIdentity(identity); 130 } 131 } 132 }, clientId); 133 } catch (RemoteException e) { 134 throw e.rethrowFromSystemServer(); 135 } 136 } 137 138 /** 139 * This API is used by the client to unregister their profile with the 140 * Tuner Resource manager. 141 * 142 * @param clientId the client id that needs to be unregistered. 143 */ unregisterClientProfile(int clientId)144 public void unregisterClientProfile(int clientId) { 145 try { 146 mService.unregisterClientProfile(clientId); 147 } catch (RemoteException e) { 148 throw e.rethrowFromSystemServer(); 149 } 150 } 151 152 /** 153 * This API is used by client to update its registered {@link ResourceClientProfile}. 154 * 155 * <p>We recommend creating a new tuner instance for different use cases instead of using this 156 * API since different use cases may need different resources. 157 * 158 * <p>If TIS updates use case, it needs to ensure underneath resources are exchangeable between 159 * two different use cases. 160 * 161 * <p>Only the arbitrary priority and niceValue are allowed to be updated. 162 * 163 * @param clientId the id of the client that is updating its profile. 164 * @param priority the priority that the client would like to update to. 165 * @param niceValue the nice value that the client would like to update to. 166 * 167 * @return true if the update is successful. 168 */ updateClientPriority(int clientId, int priority, int niceValue)169 public boolean updateClientPriority(int clientId, int priority, int niceValue) { 170 boolean result = false; 171 try { 172 result = mService.updateClientPriority(clientId, priority, niceValue); 173 } catch (RemoteException e) { 174 throw e.rethrowFromSystemServer(); 175 } 176 return result; 177 } 178 179 /** 180 * Updates the current TRM of the TunerHAL Frontend information. 181 * 182 * <p><strong>Note:</strong> This update must happen before the first 183 * {@link #requestFrontend(TunerFrontendRequest, int[])} and 184 * {@link #releaseFrontend(int, int)} call. 185 * 186 * @param infos an array of the available {@link TunerFrontendInfo} information. 187 */ setFrontendInfoList(@onNull TunerFrontendInfo[] infos)188 public void setFrontendInfoList(@NonNull TunerFrontendInfo[] infos) { 189 try { 190 mService.setFrontendInfoList(infos); 191 } catch (RemoteException e) { 192 throw e.rethrowFromSystemServer(); 193 } 194 } 195 196 /** 197 * Updates the TRM of the current CAS information. 198 * 199 * <p><strong>Note:</strong> This update must happen before the first 200 * {@link #requestCasSession(CasSessionRequest, int[])} and {@link #releaseCasSession(int, int)} 201 * call. 202 * 203 * @param casSystemId id of the updating CAS system. 204 * @param maxSessionNum the max session number of the CAS system that is updated. 205 */ updateCasInfo(int casSystemId, int maxSessionNum)206 public void updateCasInfo(int casSystemId, int maxSessionNum) { 207 try { 208 mService.updateCasInfo(casSystemId, maxSessionNum); 209 } catch (RemoteException e) { 210 throw e.rethrowFromSystemServer(); 211 } 212 } 213 214 /** 215 * Updates the TRM of the current Lnb information. 216 * 217 * <p><strong>Note:</strong> This update must happen before the first 218 * {@link #requestLnb(TunerLnbRequest, int[])} and {@link #releaseLnb(int, int)} call. 219 * 220 * @param lnbIds ids of the updating lnbs. 221 */ setLnbInfoList(int[] lnbIds)222 public void setLnbInfoList(int[] lnbIds) { 223 try { 224 mService.setLnbInfoList(lnbIds); 225 } catch (RemoteException e) { 226 throw e.rethrowFromSystemServer(); 227 } 228 } 229 230 /** 231 * Requests a frontend resource. 232 * 233 * <p>There are three possible scenarios: 234 * <ul> 235 * <li>If there is frontend available, the API would send the id back. 236 * 237 * <li>If no Frontend is available but the current request info can show higher priority than 238 * other uses of Frontend, the API will send 239 * {@link IResourcesReclaimListener#onReclaimResources()} to the {@link Tuner}. Tuner would 240 * handle the resource reclaim on the holder of lower priority and notify the holder of its 241 * resource loss. 242 * 243 * <li>If no frontend can be granted, the API would return false. 244 * <ul> 245 * 246 * <p><strong>Note:</strong> {@link #setFrontendInfoList(TunerFrontendInfo[])} must be called 247 * before this request. 248 * 249 * @param request {@link TunerFrontendRequest} information of the current request. 250 * @param frontendHandle a one-element array to return the granted frontendHandle. If 251 * no frontend granted, this will return {@link #INVALID_RESOURCE_HANDLE}. 252 * 253 * @return true if there is frontend granted. 254 */ requestFrontend(@onNull TunerFrontendRequest request, @Nullable int[] frontendHandle)255 public boolean requestFrontend(@NonNull TunerFrontendRequest request, 256 @Nullable int[] frontendHandle) { 257 boolean result = false; 258 try { 259 result = mService.requestFrontend(request, frontendHandle); 260 } catch (RemoteException e) { 261 throw e.rethrowFromSystemServer(); 262 } 263 return result; 264 } 265 266 /** 267 * Requests from the client to share frontend with an existing client. 268 * 269 * <p><strong>Note:</strong> {@link #setFrontendInfoList(TunerFrontendInfo[])} must be called 270 * before this request. 271 * 272 * @param selfClientId the id of the client that sends the request. 273 * @param targetClientId the id of the client to share the frontend with. 274 */ shareFrontend(int selfClientId, int targetClientId)275 public void shareFrontend(int selfClientId, int targetClientId) { 276 try { 277 mService.shareFrontend(selfClientId, targetClientId); 278 } catch (RemoteException e) { 279 throw e.rethrowFromSystemServer(); 280 } 281 } 282 283 /** 284 * Requests a Tuner Demux resource. 285 * 286 * <p>There are three possible scenarios: 287 * <ul> 288 * <li>If there is Demux available, the API would send the handle back. 289 * 290 * <li>If no Demux is available but the current request has a higher priority than other uses of 291 * demuxes, the API will send {@link IResourcesReclaimListener#onReclaimResources()} to the 292 * {@link Tuner}. Tuner would handle the resource reclaim on the holder of lower priority and 293 * notify the holder of its resource loss. 294 * 295 * <li>If no Demux system can be granted, the API would return false. 296 * <ul> 297 * 298 * @param request {@link TunerDemuxRequest} information of the current request. 299 * @param demuxHandle a one-element array to return the granted Demux handle. 300 * If no Demux granted, this will return {@link #INVALID_RESOURCE_HANDLE}. 301 * 302 * @return true if there is Demux granted. 303 */ requestDemux(@onNull TunerDemuxRequest request, @NonNull int[] demuxHandle)304 public boolean requestDemux(@NonNull TunerDemuxRequest request, @NonNull int[] demuxHandle) { 305 boolean result = false; 306 try { 307 result = mService.requestDemux(request, demuxHandle); 308 } catch (RemoteException e) { 309 throw e.rethrowFromSystemServer(); 310 } 311 return result; 312 } 313 314 /** 315 * Requests a Tuner Descrambler resource. 316 * 317 * <p>There are three possible scenarios: 318 * <ul> 319 * <li>If there is Descrambler available, the API would send the handle back. 320 * 321 * <li>If no Descrambler is available but the current request has a higher priority than other 322 * uses of descramblers, the API will send 323 * {@link IResourcesReclaimListener#onReclaimResources()} to the {@link Tuner}. Tuner would 324 * handle the resource reclaim on the holder of lower priority and notify the holder of its 325 * resource loss. 326 * 327 * <li>If no Descrambler system can be granted, the API would return false. 328 * <ul> 329 * 330 * @param request {@link TunerDescramblerRequest} information of the current request. 331 * @param descramblerHandle a one-element array to return the granted Descrambler handle. 332 * If no Descrambler granted, this will return 333 * {@link #INVALID_RESOURCE_HANDLE}. 334 * 335 * @return true if there is Descrambler granted. 336 */ requestDescrambler(@onNull TunerDescramblerRequest request, @NonNull int[] descramblerHandle)337 public boolean requestDescrambler(@NonNull TunerDescramblerRequest request, 338 @NonNull int[] descramblerHandle) { 339 boolean result = false; 340 try { 341 result = mService.requestDescrambler(request, descramblerHandle); 342 } catch (RemoteException e) { 343 throw e.rethrowFromSystemServer(); 344 } 345 return result; 346 } 347 348 /** 349 * Requests a CAS session resource. 350 * 351 * <p>There are three possible scenarios: 352 * <ul> 353 * <li>If there is Cas session available, the API would send the id back. 354 * 355 * <li>If no Cas system is available but the current request info can show higher priority than 356 * other uses of the cas sessions under the requested cas system, the API will send 357 * {@link IResourcesReclaimListener#onReclaimResources()} to the {@link Tuner}. Tuner would 358 * handle the resource reclaim on the holder of lower priority and notify the holder of its 359 * resource loss. 360 * 361 * <p><strong>Note:</strong> {@link #updateCasInfo(int, int)} must be called before this 362 * request. 363 * 364 * @param request {@link CasSessionRequest} information of the current request. 365 * @param casSessionHandle a one-element array to return the granted cas session handel. 366 * If no CAS granted, this will return {@link #INVALID_RESOURCE_HANDLE}. 367 * 368 * @return true if there is CAS session granted. 369 */ requestCasSession(@onNull CasSessionRequest request, @NonNull int[] casSessionHandle)370 public boolean requestCasSession(@NonNull CasSessionRequest request, 371 @NonNull int[] casSessionHandle) { 372 boolean result = false; 373 try { 374 result = mService.requestCasSession(request, casSessionHandle); 375 } catch (RemoteException e) { 376 throw e.rethrowFromSystemServer(); 377 } 378 return result; 379 } 380 381 /** 382 * Requests a Tuner Lnb resource. 383 * 384 * <p>There are three possible scenarios: 385 * <ul> 386 * <li>If there is Lnb available, the API would send the id back. 387 * 388 * <li>If no Lnb is available but the current request has a higher priority than other uses of 389 * lnbs, the API will send {@link IResourcesReclaimListener#onReclaimResources()} to the 390 * {@link Tuner}. Tuner would handle the resource reclaim on the holder of lower priority and 391 * notify the holder of its resource loss. 392 * 393 * <li>If no Lnb system can be granted, the API would return false. 394 * <ul> 395 * 396 * <p><strong>Note:</strong> {@link #setLnbInfoList(int[])} must be called before this request. 397 * 398 * @param request {@link TunerLnbRequest} information of the current request. 399 * @param lnbHandle a one-element array to return the granted Lnb handle. 400 * If no Lnb granted, this will return {@link #INVALID_RESOURCE_HANDLE}. 401 * 402 * @return true if there is Lnb granted. 403 */ requestLnb(@onNull TunerLnbRequest request, @NonNull int[] lnbHandle)404 public boolean requestLnb(@NonNull TunerLnbRequest request, @NonNull int[] lnbHandle) { 405 boolean result = false; 406 try { 407 result = mService.requestLnb(request, lnbHandle); 408 } catch (RemoteException e) { 409 throw e.rethrowFromSystemServer(); 410 } 411 return result; 412 } 413 414 /** 415 * Notifies the TRM that the given frontend has been released. 416 * 417 * <p>Client must call this whenever it releases a Tuner frontend. 418 * 419 * <p><strong>Note:</strong> {@link #setFrontendInfoList(TunerFrontendInfo[])} must be called 420 * before this release. 421 * 422 * @param frontendHandle the handle of the released frontend. 423 * @param clientId the id of the client that is releasing the frontend. 424 */ releaseFrontend(int frontendHandle, int clientId)425 public void releaseFrontend(int frontendHandle, int clientId) { 426 try { 427 mService.releaseFrontend(frontendHandle, clientId); 428 } catch (RemoteException e) { 429 throw e.rethrowFromSystemServer(); 430 } 431 } 432 433 /** 434 * Notifies the TRM that the Demux with the given handle has been released. 435 * 436 * <p>Client must call this whenever it releases an Demux. 437 * 438 * @param demuxHandle the handle of the released Tuner Demux. 439 * @param clientId the id of the client that is releasing the demux. 440 */ releaseDemux(int demuxHandle, int clientId)441 public void releaseDemux(int demuxHandle, int clientId) { 442 try { 443 mService.releaseDemux(demuxHandle, clientId); 444 } catch (RemoteException e) { 445 throw e.rethrowFromSystemServer(); 446 } 447 } 448 449 /** 450 * Notifies the TRM that the Descrambler with the given handle has been released. 451 * 452 * <p>Client must call this whenever it releases an Descrambler. 453 * 454 * @param descramblerHandle the handle of the released Tuner Descrambler. 455 * @param clientId the id of the client that is releasing the descrambler. 456 */ releaseDescrambler(int descramblerHandle, int clientId)457 public void releaseDescrambler(int descramblerHandle, int clientId) { 458 try { 459 mService.releaseDescrambler(descramblerHandle, clientId); 460 } catch (RemoteException e) { 461 throw e.rethrowFromSystemServer(); 462 } 463 } 464 465 /** 466 * Notifies the TRM that the given Cas session has been released. 467 * 468 * <p>Client must call this whenever it releases a Cas session. 469 * 470 * <p><strong>Note:</strong> {@link #updateCasInfo(int, int)} must be called before this 471 * release. 472 * 473 * @param casSessionHandle the handle of the released CAS session. 474 * @param clientId the id of the client that is releasing the cas session. 475 */ releaseCasSession(int casSessionHandle, int clientId)476 public void releaseCasSession(int casSessionHandle, int clientId) { 477 try { 478 mService.releaseCasSession(casSessionHandle, clientId); 479 } catch (RemoteException e) { 480 throw e.rethrowFromSystemServer(); 481 } 482 } 483 484 /** 485 * Notifies the TRM that the Lnb with the given id has been released. 486 * 487 * <p>Client must call this whenever it releases an Lnb. 488 * 489 * <p><strong>Note:</strong> {@link #setLnbInfoList(int[])} must be called before this release. 490 * 491 * @param lnbHandle the handle of the released Tuner Lnb. 492 * @param clientId the id of the client that is releasing the lnb. 493 */ releaseLnb(int lnbHandle, int clientId)494 public void releaseLnb(int lnbHandle, int clientId) { 495 try { 496 mService.releaseLnb(lnbHandle, clientId); 497 } catch (RemoteException e) { 498 throw e.rethrowFromSystemServer(); 499 } 500 } 501 502 /** 503 * Compare two clients' priority. 504 * 505 * @param challengerProfile the {@link ResourceClientProfile} of the challenger. 506 * @param holderProfile the {@link ResourceClientProfile} of the holder of the resource. 507 * 508 * @return true if the challenger has higher priority than the holder. 509 */ isHigherPriority(ResourceClientProfile challengerProfile, ResourceClientProfile holderProfile)510 public boolean isHigherPriority(ResourceClientProfile challengerProfile, 511 ResourceClientProfile holderProfile) { 512 try { 513 return mService.isHigherPriority(challengerProfile, holderProfile); 514 } catch (RemoteException e) { 515 throw e.rethrowFromSystemServer(); 516 } 517 } 518 519 /** 520 * Interface used to receive events from TunerResourceManager. 521 */ 522 public abstract static class ResourcesReclaimListener { 523 /* 524 * To reclaim all the resources of the callack owner. 525 */ onReclaimResources()526 public abstract void onReclaimResources(); 527 } 528 } 529