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