Merge "Complete the Cas System request/release/update implementation in TRM" into rvc-dev

This commit is contained in:
Amy Zhang
2020-04-21 18:56:39 +00:00
committed by Android (Google) Code Review
7 changed files with 552 additions and 177 deletions

View File

@@ -388,7 +388,7 @@ public final class MediaCas implements AutoCloseable {
@Override
public void onReclaimResources() {
synchronized (mSessionMap) {
mSessionMap.forEach((casSession, sessionResourceId) -> casSession.close());
mSessionMap.forEach((casSession, sessionResourceHandle) -> casSession.close());
}
mEventHandler.sendMessage(mEventHandler.obtainMessage(
EventHandler.MSG_CAS_RESOURCE_LOST));
@@ -868,7 +868,7 @@ public final class MediaCas implements AutoCloseable {
}
}
private int getSessionResourceId() throws MediaCasException {
private int getSessionResourceHandle() throws MediaCasException {
validateInternalStates();
int[] sessionResourceHandle = new int[1];
@@ -881,14 +881,14 @@ public final class MediaCas implements AutoCloseable {
"insufficient resource to Open Session");
}
}
return sessionResourceHandle[0];
return sessionResourceHandle[0];
}
private void addSessionToResourceMap(Session session, int sessionResourceId) {
private void addSessionToResourceMap(Session session, int sessionResourceHandle) {
if (sessionResourceId != -1) {
if (sessionResourceHandle != TunerResourceManager.INVALID_RESOURCE_HANDLE) {
synchronized (mSessionMap) {
mSessionMap.put(session, sessionResourceId);
mSessionMap.put(session, sessionResourceHandle);
}
}
}
@@ -918,13 +918,13 @@ public final class MediaCas implements AutoCloseable {
* @throws MediaCasStateException for CAS-specific state exceptions.
*/
public Session openSession() throws MediaCasException {
int sessionResourceId = getSessionResourceId();
int sessionResourceHandle = getSessionResourceHandle();
try {
OpenSessionCallback cb = new OpenSessionCallback();
mICas.openSession(cb);
MediaCasException.throwExceptionIfNeeded(cb.mStatus);
addSessionToResourceMap(cb.mSession, sessionResourceId);
addSessionToResourceMap(cb.mSession, sessionResourceHandle);
return cb.mSession;
} catch (RemoteException e) {
cleanupAndRethrowIllegalState();
@@ -952,7 +952,7 @@ public final class MediaCas implements AutoCloseable {
@Nullable
public Session openSession(@SessionUsage int sessionUsage, @ScramblingMode int scramblingMode)
throws MediaCasException {
int sessionResourceId = getSessionResourceId();
int sessionResourceHandle = getSessionResourceHandle();
if (mICasV12 == null) {
Log.d(TAG, "Open Session with scrambling mode is only supported by cas@1.2+ interface");
@@ -963,7 +963,7 @@ public final class MediaCas implements AutoCloseable {
OpenSession_1_2_Callback cb = new OpenSession_1_2_Callback();
mICasV12.openSession_1_2(sessionUsage, scramblingMode, cb);
MediaCasException.throwExceptionIfNeeded(cb.mStatus);
addSessionToResourceMap(cb.mSession, sessionResourceId);
addSessionToResourceMap(cb.mSession, sessionResourceHandle);
return cb.mSession;
} catch (RemoteException e) {
cleanupAndRethrowIllegalState();

View File

@@ -218,11 +218,11 @@ interface ITunerResourceManager {
* <p><strong>Note:</strong> {@link #updateCasInfo(int, int)} must be called before this request.
*
* @param request {@link CasSessionRequest} information of the current request.
* @param sessionResourceId a one-element array to return the granted cas session id.
* @param casSessionHandle a one-element array to return the granted cas session handle.
*
* @return true if there is CAS session granted.
*/
boolean requestCasSession(in CasSessionRequest request, out int[] sessionResourceId);
boolean requestCasSession(in CasSessionRequest request, out int[] casSessionHandle);
/*
* This API is used by the Tuner framework to request an available Lnb from the TunerHAL.
@@ -276,7 +276,7 @@ interface ITunerResourceManager {
*
* <p>Client must call this whenever it releases a descrambler.
*
* @param demuxHandle the handle of the released Tuner Descrambler.
* @param descramblerHandle the handle of the released Tuner Descrambler.
* @param clientId the id of the client that is releasing the descrambler.
*/
void releaseDescrambler(in int descramblerHandle, int clientId);
@@ -288,10 +288,10 @@ interface ITunerResourceManager {
*
* <p><strong>Note:</strong> {@link #updateCasInfo(int, int)} must be called before this release.
*
* @param sessionResourceId the id of the released CAS session.
* @param casSessionHandle the handle of the released CAS session.
* @param clientId the id of the client that is releasing the cas session.
*/
void releaseCasSession(in int sessionResourceId, int clientId);
void releaseCasSession(in int casSessionHandle, int clientId);
/*
* Notifies the TRM that the Lnb with the given handle was released.

View File

@@ -362,17 +362,16 @@ public class TunerResourceManager {
* request.
*
* @param request {@link CasSessionRequest} information of the current request.
* @param sessionResourceId a one-element array to return the granted cas session id.
* If no CAS granted, this will return
* {@link #INVALID_CAS_SESSION_RESOURCE_ID}.
* @param casSessionHandle a one-element array to return the granted cas session handel.
* If no CAS granted, this will return {@link #INVALID_RESOURCE_HANDLE}.
*
* @return true if there is CAS session granted.
*/
public boolean requestCasSession(@NonNull CasSessionRequest request,
@NonNull int[] sessionResourceId) {
@NonNull int[] casSessionHandle) {
boolean result = false;
try {
result = mService.requestCasSession(request, sessionResourceId);
result = mService.requestCasSession(request, casSessionHandle);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -471,12 +470,12 @@ public class TunerResourceManager {
* <p><strong>Note:</strong> {@link #updateCasInfo(int, int)} must be called before this
* release.
*
* @param sessionResourceId the id of the released CAS session.
* @param casSessionHandle the handle of the released CAS session.
* @param clientId the id of the client that is releasing the cas session.
*/
public void releaseCasSession(int sessionResourceId, int clientId) {
public void releaseCasSession(int casSessionHandle, int clientId) {
try {
mService.releaseCasSession(sessionResourceId, clientId);
mService.releaseCasSession(casSessionHandle, clientId);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}

View File

@@ -0,0 +1,152 @@
/*
* Copyright 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.server.tv.tunerresourcemanager;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
/**
* A Cas resource object used by the Tuner Resource Manager to record the cas
* information.
*
* @hide
*/
public final class CasResource {
private final int mSystemId;
private int mMaxSessionNum;
private int mAvailableSessionNum;
/**
* The owner clients' ids when part of the Cas is occupied.
*/
private Map<Integer, Integer> mOwnerClientIdsToSessionNum = new HashMap<>();
private CasResource(Builder builder) {
this.mSystemId = builder.mSystemId;
this.mMaxSessionNum = builder.mMaxSessionNum;
this.mAvailableSessionNum = builder.mMaxSessionNum;
}
public int getSystemId() {
return mSystemId;
}
public int getMaxSessionNum() {
return mMaxSessionNum;
}
public int getUsedSessionNum() {
return (mMaxSessionNum - mAvailableSessionNum);
}
public boolean isFullyUsed() {
return mAvailableSessionNum == 0;
}
/**
* Update max session number.
*
* @param maxSessionNum the new max session num.
*/
public void updateMaxSessionNum(int maxSessionNum) {
mAvailableSessionNum = Math.max(
0, mAvailableSessionNum + (maxSessionNum - mMaxSessionNum));
mMaxSessionNum = maxSessionNum;
}
/**
* Set an owner for the cas
*
* @param ownerId the client id of the owner.
*/
public void setOwner(int ownerId) {
int sessionNum = mOwnerClientIdsToSessionNum.get(ownerId) == null
? 1 : (mOwnerClientIdsToSessionNum.get(ownerId) + 1);
mOwnerClientIdsToSessionNum.put(ownerId, sessionNum);
mAvailableSessionNum--;
}
/**
* Remove an owner of the Cas.
*
* @param ownerId the removing client id of the owner.
*/
public void removeOwner(int ownerId) {
mAvailableSessionNum += mOwnerClientIdsToSessionNum.get(ownerId);
mOwnerClientIdsToSessionNum.remove(ownerId);
}
public Set<Integer> getOwnerClientIds() {
return mOwnerClientIdsToSessionNum.keySet();
}
@Override
public String toString() {
return "CasResource[systemId=" + this.mSystemId
+ ", isFullyUsed=" + (this.mAvailableSessionNum == 0)
+ ", maxSessionNum=" + this.mMaxSessionNum
+ ", ownerClients=" + ownersMapToString() + "]";
}
/**
* Builder class for {@link CasResource}.
*/
public static class Builder {
private int mSystemId;
private int mMaxSessionNum;
Builder(int systemId) {
this.mSystemId = systemId;
}
/**
* Builder for {@link CasResource}.
*
* @param maxSessionNum the max session num the current Cas has.
*/
public Builder maxSessionNum(int maxSessionNum) {
this.mMaxSessionNum = maxSessionNum;
return this;
}
/**
* Build a {@link CasResource}.
*
* @return {@link CasResource}.
*/
public CasResource build() {
CasResource cas = new CasResource(this);
return cas;
}
}
private String ownersMapToString() {
StringBuilder string = new StringBuilder("{");
for (int clienId : mOwnerClientIdsToSessionNum.keySet()) {
string.append(" clientId=")
.append(clienId)
.append(", owns session num=")
.append(mOwnerClientIdsToSessionNum.get(clienId))
.append(",");
}
return string.append("}").toString();
}
}

View File

@@ -27,6 +27,7 @@ import java.util.Set;
public final class ClientProfile {
public static final int INVALID_GROUP_ID = -1;
public static final int INVALID_RESOURCE_ID = -1;
/**
* Client id sent to the client when registering with
@@ -56,7 +57,6 @@ public final class ClientProfile {
* also lose their resources.
*/
private int mGroupId = INVALID_GROUP_ID;
/**
* Optional nice value for TRM to reduce clients priority.
*/
@@ -72,6 +72,11 @@ public final class ClientProfile {
*/
private Set<Integer> mUsingLnbIds = new HashSet<>();
/**
* List of the Cas system ids that are used by the current client.
*/
private int mUsingCasSystemId = INVALID_RESOURCE_ID;
/**
* Optional arbitrary priority value given by the client.
*
@@ -171,12 +176,33 @@ public final class ClientProfile {
mUsingLnbIds.remove(lnbId);
}
/**
* Set when the client starts to use a Cas system.
*
* @param casSystemId cas being used.
*/
public void useCas(int casSystemId) {
mUsingCasSystemId = casSystemId;
}
public int getInUseCasSystemId() {
return mUsingCasSystemId;
}
/**
* Called when the client released a Cas System.
*/
public void releaseCas() {
mUsingCasSystemId = INVALID_RESOURCE_ID;
}
/**
* Called to reclaim all the resources being used by the current client.
*/
public void reclaimAllResources() {
mUsingFrontendIds.clear();
mUsingLnbIds.clear();
mUsingCasSystemId = INVALID_RESOURCE_ID;
}
@Override

View File

@@ -65,6 +65,8 @@ public class TunerResourceManagerService extends SystemService {
private Map<Integer, FrontendResource> mFrontendResources = new HashMap<>();
// Map of the current available lnb resources
private Map<Integer, LnbResource> mLnbResources = new HashMap<>();
// Map of the current available Cas resources
private Map<Integer, CasResource> mCasResources = new HashMap<>();
@GuardedBy("mLock")
private Map<Integer, ResourcesReclaimListenerRecord> mListeners = new HashMap<>();
@@ -158,10 +160,8 @@ public class TunerResourceManagerService extends SystemService {
@Override
public void updateCasInfo(int casSystemId, int maxSessionNum) {
enforceTrmAccessPermission("updateCasInfo");
if (DEBUG) {
Slog.d(TAG,
"updateCasInfo(casSystemId=" + casSystemId
+ ", maxSessionNum=" + maxSessionNum + ")");
synchronized (mLock) {
updateCasInfoInternal(casSystemId, maxSessionNum);
}
}
@@ -185,11 +185,11 @@ public class TunerResourceManagerService extends SystemService {
throw new RemoteException("frontendHandle can't be null");
}
synchronized (mLock) {
try {
return requestFrontendInternal(request, frontendHandle);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
if (!checkClientExists(request.getClientId())) {
throw new RemoteException("Request frontend from unregistered client:"
+ request.getClientId());
}
return requestFrontendInternal(request, frontendHandle);
}
}
@@ -211,32 +211,45 @@ public class TunerResourceManagerService extends SystemService {
throw new RemoteException("demuxHandle can't be null");
}
synchronized (mLock) {
if (!checkClientExists(request.getClientId())) {
throw new RemoteException("Request demux from unregistered client:"
+ request.getClientId());
}
return requestDemuxInternal(request, demuxHandle);
}
}
@Override
public boolean requestDescrambler(@NonNull TunerDescramblerRequest request,
@NonNull int[] descrambleHandle) throws RemoteException {
@NonNull int[] descramblerHandle) throws RemoteException {
enforceDescramblerAccessPermission("requestDescrambler");
enforceTrmAccessPermission("requestDescrambler");
if (descrambleHandle == null) {
throw new RemoteException("descrambleHandle can't be null");
if (descramblerHandle == null) {
throw new RemoteException("descramblerHandle can't be null");
}
synchronized (mLock) {
return requestDescramblerInternal(request, descrambleHandle);
if (!checkClientExists(request.getClientId())) {
throw new RemoteException("Request descrambler from unregistered client:"
+ request.getClientId());
}
return requestDescramblerInternal(request, descramblerHandle);
}
}
@Override
public boolean requestCasSession(
@NonNull CasSessionRequest request, @NonNull int[] sessionResourceHandle) {
public boolean requestCasSession(@NonNull CasSessionRequest request,
@NonNull int[] casSessionHandle) throws RemoteException {
enforceTrmAccessPermission("requestCasSession");
if (DEBUG) {
Slog.d(TAG, "requestCasSession(request=" + request + ")");
if (casSessionHandle == null) {
throw new RemoteException("casSessionHandle can't be null");
}
synchronized (mLock) {
if (!checkClientExists(request.getClientId())) {
throw new RemoteException("Request cas from unregistered client:"
+ request.getClientId());
}
return requestCasSessionInternal(request, casSessionHandle);
}
return true;
}
@Override
@@ -248,11 +261,11 @@ public class TunerResourceManagerService extends SystemService {
throw new RemoteException("lnbHandle can't be null");
}
synchronized (mLock) {
try {
return requestLnbInternal(request, lnbHandle);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
if (!checkClientExists(request.getClientId())) {
throw new RemoteException("Request lnb from unregistered client:"
+ request.getClientId());
}
return requestLnbInternal(request, lnbHandle);
}
}
@@ -264,15 +277,20 @@ public class TunerResourceManagerService extends SystemService {
frontendHandle)) {
throw new RemoteException("frontendHandle can't be invalid");
}
int frontendId = getResourceIdFromHandle(frontendHandle);
FrontendResource fe = getFrontendResource(frontendId);
if (fe == null) {
throw new RemoteException("Releasing frontend does not exist.");
}
if (fe.getOwnerClientId() != clientId) {
throw new RemoteException("Client is not the current owner of the releasing fe.");
}
synchronized (mLock) {
if (!checkClientExists(clientId)) {
throw new RemoteException("Release frontend from unregistered client:"
+ clientId);
}
int frontendId = getResourceIdFromHandle(frontendHandle);
FrontendResource fe = getFrontendResource(frontendId);
if (fe == null) {
throw new RemoteException("Releasing frontend does not exist.");
}
if (fe.getOwnerClientId() != clientId) {
throw new RemoteException(
"Client is not the current owner of the releasing fe.");
}
releaseFrontendInternal(fe);
}
}
@@ -296,10 +314,26 @@ public class TunerResourceManagerService extends SystemService {
}
@Override
public void releaseCasSession(int sessionResourceId, int clientId) {
public void releaseCasSession(int casSessionHandle, int clientId) throws RemoteException {
enforceTrmAccessPermission("releaseCasSession");
if (DEBUG) {
Slog.d(TAG, "releaseCasSession(sessionResourceId=" + sessionResourceId + ")");
if (!validateResourceHandle(
TunerResourceManager.TUNER_RESOURCE_TYPE_CAS_SESSION, casSessionHandle)) {
throw new RemoteException("casSessionHandle can't be invalid");
}
synchronized (mLock) {
if (!checkClientExists(clientId)) {
throw new RemoteException("Release cas from unregistered client:" + clientId);
}
int casSystemId = getClientProfile(clientId).getInUseCasSystemId();
CasResource cas = getCasResource(casSystemId);
if (cas == null) {
throw new RemoteException("Releasing cas does not exist.");
}
if (!cas.getOwnerClientIds().contains(clientId)) {
throw new RemoteException(
"Client is not the current owner of the releasing cas.");
}
releaseCasSessionInternal(cas, clientId);
}
}
@@ -310,6 +344,9 @@ public class TunerResourceManagerService extends SystemService {
if (!validateResourceHandle(TunerResourceManager.TUNER_RESOURCE_TYPE_LNB, lnbHandle)) {
throw new RemoteException("lnbHandle can't be invalid");
}
if (!checkClientExists(clientId)) {
throw new RemoteException("Release lnb from unregistered client:" + clientId);
}
int lnbId = getResourceIdFromHandle(lnbHandle);
LnbResource lnb = getLnbResource(lnbId);
if (lnb == null) {
@@ -465,17 +502,42 @@ public class TunerResourceManagerService extends SystemService {
}
@VisibleForTesting
protected boolean requestFrontendInternal(TunerFrontendRequest request, int[] frontendHandle)
throws RemoteException {
protected void updateCasInfoInternal(int casSystemId, int maxSessionNum) {
if (DEBUG) {
Slog.d(TAG,
"updateCasInfo(casSystemId=" + casSystemId
+ ", maxSessionNum=" + maxSessionNum + ")");
}
// If maxSessionNum is 0, removing the Cas Resource.
if (maxSessionNum == 0) {
removeCasResource(casSystemId);
return;
}
// If the Cas exists, updates the Cas Resource accordingly.
CasResource cas = getCasResource(casSystemId);
if (cas != null) {
if (cas.getUsedSessionNum() > maxSessionNum) {
// Sort and release the short number of Cas resources.
int releasingCasResourceNum = cas.getUsedSessionNum() - maxSessionNum;
releaseLowerPriorityClientCasResources(releasingCasResourceNum);
}
cas.updateMaxSessionNum(maxSessionNum);
return;
}
// Add the new Cas Resource.
cas = new CasResource.Builder(casSystemId)
.maxSessionNum(maxSessionNum)
.build();
addCasResource(cas);
}
@VisibleForTesting
protected boolean requestFrontendInternal(TunerFrontendRequest request, int[] frontendHandle) {
if (DEBUG) {
Slog.d(TAG, "requestFrontend(request=" + request + ")");
}
frontendHandle[0] = TunerResourceManager.INVALID_RESOURCE_HANDLE;
if (!checkClientExists(request.getClientId())) {
Slog.e(TAG, "Request frontend from unregistered client:" + request.getClientId());
return false;
}
ClientProfile requestClient = getClientProfile(request.getClientId());
int grantingFrontendId = -1;
int inUseLowestPriorityFrId = -1;
@@ -496,7 +558,7 @@ public class TunerResourceManagerService extends SystemService {
} else if (grantingFrontendId < 0) {
// Record the frontend id with the lowest client priority among all the
// in use frontends when no available frontend has been found.
int priority = getOwnerClientPriority(fr);
int priority = getOwnerClientPriority(fr.getOwnerClientId());
if (currentLowestPriority > priority) {
inUseLowestPriorityFrId = fr.getId();
currentLowestPriority = priority;
@@ -530,17 +592,12 @@ public class TunerResourceManagerService extends SystemService {
}
@VisibleForTesting
protected boolean requestLnbInternal(TunerLnbRequest request, int[] lnbHandle)
throws RemoteException {
protected boolean requestLnbInternal(TunerLnbRequest request, int[] lnbHandle) {
if (DEBUG) {
Slog.d(TAG, "requestLnb(request=" + request + ")");
}
lnbHandle[0] = TunerResourceManager.INVALID_RESOURCE_HANDLE;
if (!checkClientExists(request.getClientId())) {
Slog.e(TAG, "Request lnb from unregistered client:" + request.getClientId());
return false;
}
ClientProfile requestClient = getClientProfile(request.getClientId());
int grantingLnbId = -1;
int inUseLowestPriorityLnbId = -1;
@@ -554,7 +611,7 @@ public class TunerResourceManagerService extends SystemService {
} else {
// Record the lnb id with the lowest client priority among all the
// in use lnb when no available lnb has been found.
int priority = getOwnerClientPriority(lnb);
int priority = getOwnerClientPriority(lnb.getOwnerClientId());
if (currentLowestPriority > priority) {
inUseLowestPriorityLnbId = lnb.getId();
currentLowestPriority = priority;
@@ -588,7 +645,55 @@ public class TunerResourceManagerService extends SystemService {
}
@VisibleForTesting
void releaseFrontendInternal(FrontendResource fe) {
protected boolean requestCasSessionInternal(CasSessionRequest request, int[] casSessionHandle) {
if (DEBUG) {
Slog.d(TAG, "requestCasSession(request=" + request + ")");
}
CasResource cas = getCasResource(request.getCasSystemId());
// Unregistered Cas System is treated as having unlimited sessions.
if (cas == null) {
cas = new CasResource.Builder(request.getCasSystemId())
.maxSessionNum(Integer.MAX_VALUE)
.build();
addCasResource(cas);
}
casSessionHandle[0] = TunerResourceManager.INVALID_RESOURCE_HANDLE;
ClientProfile requestClient = getClientProfile(request.getClientId());
int lowestPriorityOwnerId = -1;
// Priority max value is 1000
int currentLowestPriority = MAX_CLIENT_PRIORITY + 1;
if (!cas.isFullyUsed()) {
casSessionHandle[0] = generateResourceHandle(
TunerResourceManager.TUNER_RESOURCE_TYPE_CAS_SESSION, cas.getSystemId());
updateCasClientMappingOnNewGrant(request.getCasSystemId(), request.getClientId());
return true;
}
for (int ownerId : cas.getOwnerClientIds()) {
// Record the client id with lowest priority that is using the current Cas system.
int priority = getOwnerClientPriority(ownerId);
if (currentLowestPriority > priority) {
lowestPriorityOwnerId = ownerId;
currentLowestPriority = priority;
}
}
// When all the Cas sessions are occupied, reclaim the lowest priority client if the
// request client has higher priority.
if (lowestPriorityOwnerId > -1 && (requestClient.getPriority() > currentLowestPriority)) {
if (!reclaimResource(lowestPriorityOwnerId,
TunerResourceManager.TUNER_RESOURCE_TYPE_CAS_SESSION)) {
return false;
}
casSessionHandle[0] = generateResourceHandle(
TunerResourceManager.TUNER_RESOURCE_TYPE_CAS_SESSION, cas.getSystemId());
updateCasClientMappingOnNewGrant(request.getCasSystemId(), request.getClientId());
return true;
}
return false;
}
@VisibleForTesting
protected void releaseFrontendInternal(FrontendResource fe) {
if (DEBUG) {
Slog.d(TAG, "releaseFrontend(id=" + fe.getId() + ")");
}
@@ -596,7 +701,7 @@ public class TunerResourceManagerService extends SystemService {
}
@VisibleForTesting
void releaseLnbInternal(LnbResource lnb) {
protected void releaseLnbInternal(LnbResource lnb) {
if (DEBUG) {
Slog.d(TAG, "releaseLnb(lnbId=" + lnb.getId() + ")");
}
@@ -604,7 +709,15 @@ public class TunerResourceManagerService extends SystemService {
}
@VisibleForTesting
boolean requestDemuxInternal(TunerDemuxRequest request, int[] demuxHandle) {
protected void releaseCasSessionInternal(CasResource cas, int ownerClientId) {
if (DEBUG) {
Slog.d(TAG, "releaseCasSession(sessionResourceId=" + cas.getSystemId() + ")");
}
updateCasClientMappingOnRelease(cas, ownerClientId);
}
@VisibleForTesting
protected boolean requestDemuxInternal(TunerDemuxRequest request, int[] demuxHandle) {
if (DEBUG) {
Slog.d(TAG, "requestDemux(request=" + request + ")");
}
@@ -614,7 +727,8 @@ public class TunerResourceManagerService extends SystemService {
}
@VisibleForTesting
boolean requestDescramblerInternal(TunerDescramblerRequest request, int[] descramblerHandle) {
protected boolean requestDescramblerInternal(
TunerDescramblerRequest request, int[] descramblerHandle) {
if (DEBUG) {
Slog.d(TAG, "requestDescrambler(request=" + request + ")");
}
@@ -742,14 +856,28 @@ public class TunerResourceManagerService extends SystemService {
ownerProfile.releaseLnb(releasingLnb.getId());
}
private void updateCasClientMappingOnNewGrant(int grantingId, int ownerClientId) {
CasResource grantingCas = getCasResource(grantingId);
ClientProfile ownerProfile = getClientProfile(ownerClientId);
grantingCas.setOwner(ownerClientId);
ownerProfile.useCas(grantingId);
}
private void updateCasClientMappingOnRelease(
@NonNull CasResource releasingCas, int ownerClientId) {
ClientProfile ownerProfile = getClientProfile(ownerClientId);
releasingCas.removeOwner(ownerClientId);
ownerProfile.releaseCas();
}
/**
* Get the owner client's priority from the resource id.
*
* @param resource a in use tuner resource.
* @param clientId the owner client id.
* @return the priority of the owner client of the resource.
*/
private int getOwnerClientPriority(TunerResourceBasic resource) {
return getClientProfile(resource.getOwnerClientId()).getPriority();
private int getOwnerClientPriority(int clientId) {
return getClientProfile(clientId).getPriority();
}
@VisibleForTesting
@@ -783,6 +911,9 @@ public class TunerResourceManagerService extends SystemService {
private void removeFrontendResource(int removingId) {
FrontendResource fe = getFrontendResource(removingId);
if (fe == null) {
return;
}
if (fe.isInUse()) {
releaseFrontendInternal(fe);
}
@@ -811,12 +942,48 @@ public class TunerResourceManagerService extends SystemService {
private void removeLnbResource(int removingId) {
LnbResource lnb = getLnbResource(removingId);
if (lnb == null) {
return;
}
if (lnb.isInUse()) {
releaseLnbInternal(lnb);
}
mLnbResources.remove(removingId);
}
@VisibleForTesting
@Nullable
protected CasResource getCasResource(int systemId) {
return mCasResources.get(systemId);
}
@VisibleForTesting
protected Map<Integer, CasResource> getCasResources() {
return mCasResources;
}
private void addCasResource(CasResource newCas) {
// Update resource list and available id list
mCasResources.put(newCas.getSystemId(), newCas);
}
private void removeCasResource(int removingId) {
CasResource cas = getCasResource(removingId);
if (cas == null) {
return;
}
for (int ownerId : cas.getOwnerClientIds()) {
getClientProfile(ownerId).releaseCas();
}
mCasResources.remove(removingId);
}
private void releaseLowerPriorityClientCasResources(int releasingCasResourceNum) {
// TODO: Sort with a treemap
// select the first num client to release
}
@VisibleForTesting
@Nullable
protected ClientProfile getClientProfile(int clientId) {
@@ -830,12 +997,7 @@ public class TunerResourceManagerService extends SystemService {
}
private void removeClientProfile(int clientId) {
for (int id : getClientProfile(clientId).getInUseFrontendIds()) {
getFrontendResource(id).removeOwner();
for (int groupMemberId : getFrontendResource(id).getExclusiveGroupMemberFeIds()) {
getFrontendResource(groupMemberId).removeOwner();
}
}
reclaimingResourcesFromClient(getClientProfile(clientId));
mClientProfiles.remove(clientId);
mListeners.remove(clientId);
}
@@ -847,6 +1009,9 @@ public class TunerResourceManagerService extends SystemService {
for (Integer lnbId : profile.getInUseLnbIds()) {
getLnbResource(lnbId).removeOwner();
}
if (profile.getInUseCasSystemId() != ClientProfile.INVALID_RESOURCE_ID) {
getCasResource(profile.getInUseCasSystemId()).removeOwner(profile.getId());
}
profile.reclaimAllResources();
}

View File

@@ -26,6 +26,7 @@ import android.media.tv.ITvInputManager;
import android.media.tv.TvInputManager;
import android.media.tv.TvInputService;
import android.media.tv.tuner.frontend.FrontendSettings;
import android.media.tv.tunerresourcemanager.CasSessionRequest;
import android.media.tv.tunerresourcemanager.IResourcesReclaimListener;
import android.media.tv.tunerresourcemanager.ResourceClientProfile;
import android.media.tv.tunerresourcemanager.TunerDemuxRequest;
@@ -34,7 +35,6 @@ import android.media.tv.tunerresourcemanager.TunerFrontendInfo;
import android.media.tv.tunerresourcemanager.TunerFrontendRequest;
import android.media.tv.tunerresourcemanager.TunerLnbRequest;
import android.media.tv.tunerresourcemanager.TunerResourceManager;
import android.os.RemoteException;
import android.platform.test.annotations.Presubmit;
import androidx.test.InstrumentationRegistry;
@@ -236,12 +236,8 @@ public class TunerResourceManagerServiceTest {
TunerFrontendRequest request =
new TunerFrontendRequest(0 /*clientId*/, FrontendSettings.TYPE_DVBT);
int[] frontendHandle = new int[1];
try {
assertThat(mTunerResourceManagerService
.requestFrontendInternal(request, frontendHandle)).isFalse();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
assertThat(mTunerResourceManagerService
.requestFrontendInternal(request, frontendHandle)).isFalse();
assertThat(mTunerResourceManagerService.getResourceIdFromHandle(frontendHandle[0]))
.isEqualTo(TunerResourceManager.INVALID_RESOURCE_HANDLE);
}
@@ -264,12 +260,8 @@ public class TunerResourceManagerServiceTest {
TunerFrontendRequest request =
new TunerFrontendRequest(clientId[0] /*clientId*/, FrontendSettings.TYPE_DVBT);
int[] frontendHandle = new int[1];
try {
assertThat(mTunerResourceManagerService
.requestFrontendInternal(request, frontendHandle)).isFalse();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
assertThat(mTunerResourceManagerService
.requestFrontendInternal(request, frontendHandle)).isFalse();
assertThat(mTunerResourceManagerService.getResourceIdFromHandle(frontendHandle[0]))
.isEqualTo(TunerResourceManager.INVALID_RESOURCE_HANDLE);
}
@@ -296,12 +288,8 @@ public class TunerResourceManagerServiceTest {
TunerFrontendRequest request =
new TunerFrontendRequest(clientId[0] /*clientId*/, FrontendSettings.TYPE_DVBT);
int[] frontendHandle = new int[1];
try {
assertThat(mTunerResourceManagerService
.requestFrontendInternal(request, frontendHandle)).isTrue();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
assertThat(mTunerResourceManagerService
.requestFrontendInternal(request, frontendHandle)).isTrue();
assertThat(mTunerResourceManagerService.getResourceIdFromHandle(frontendHandle[0]))
.isEqualTo(0);
}
@@ -334,23 +322,15 @@ public class TunerResourceManagerServiceTest {
int[] frontendHandle = new int[1];
TunerFrontendRequest request =
new TunerFrontendRequest(clientId1[0] /*clientId*/, FrontendSettings.TYPE_DVBT);
try {
assertThat(mTunerResourceManagerService
.requestFrontendInternal(request, frontendHandle)).isTrue();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
assertThat(mTunerResourceManagerService
.requestFrontendInternal(request, frontendHandle)).isTrue();
assertThat(mTunerResourceManagerService.getResourceIdFromHandle(frontendHandle[0]))
.isEqualTo(infos[0].getId());
request =
new TunerFrontendRequest(clientId0[0] /*clientId*/, FrontendSettings.TYPE_DVBT);
try {
assertThat(mTunerResourceManagerService
.requestFrontendInternal(request, frontendHandle)).isTrue();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
assertThat(mTunerResourceManagerService
.requestFrontendInternal(request, frontendHandle)).isTrue();
assertThat(mTunerResourceManagerService.getResourceIdFromHandle(frontendHandle[0]))
.isEqualTo(infos[1].getId());
assertThat(mTunerResourceManagerService.getFrontendResource(infos[1].getId())
@@ -394,32 +374,20 @@ public class TunerResourceManagerServiceTest {
TunerFrontendRequest request =
new TunerFrontendRequest(clientId0[0] /*clientId*/, FrontendSettings.TYPE_DVBT);
int[] frontendHandle = new int[1];
try {
assertThat(mTunerResourceManagerService
.requestFrontendInternal(request, frontendHandle)).isTrue();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
assertThat(mTunerResourceManagerService
.requestFrontendInternal(request, frontendHandle)).isTrue();
request =
new TunerFrontendRequest(clientId1[0] /*clientId*/, FrontendSettings.TYPE_DVBT);
try {
assertThat(mTunerResourceManagerService
.requestFrontendInternal(request, frontendHandle)).isFalse();
assertThat(listener.isRelaimed()).isFalse();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
assertThat(mTunerResourceManagerService
.requestFrontendInternal(request, frontendHandle)).isFalse();
assertThat(listener.isRelaimed()).isFalse();
request =
new TunerFrontendRequest(clientId1[0] /*clientId*/, FrontendSettings.TYPE_DVBS);
try {
assertThat(mTunerResourceManagerService
.requestFrontendInternal(request, frontendHandle)).isFalse();
assertThat(listener.isRelaimed()).isFalse();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
assertThat(mTunerResourceManagerService
.requestFrontendInternal(request, frontendHandle)).isFalse();
assertThat(listener.isRelaimed()).isFalse();
}
@Test
@@ -456,12 +424,8 @@ public class TunerResourceManagerServiceTest {
TunerFrontendRequest request =
new TunerFrontendRequest(clientId0[0] /*clientId*/, FrontendSettings.TYPE_DVBT);
int[] frontendHandle = new int[1];
try {
assertThat(mTunerResourceManagerService
.requestFrontendInternal(request, frontendHandle)).isTrue();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
assertThat(mTunerResourceManagerService
.requestFrontendInternal(request, frontendHandle)).isTrue();
assertThat(mTunerResourceManagerService.getResourceIdFromHandle(frontendHandle[0]))
.isEqualTo(infos[0].getId());
assertThat(mTunerResourceManagerService.getClientProfile(clientId0[0])
@@ -470,12 +434,8 @@ public class TunerResourceManagerServiceTest {
request =
new TunerFrontendRequest(clientId1[0] /*clientId*/, FrontendSettings.TYPE_DVBS);
try {
assertThat(mTunerResourceManagerService
.requestFrontendInternal(request, frontendHandle)).isTrue();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
assertThat(mTunerResourceManagerService
.requestFrontendInternal(request, frontendHandle)).isTrue();
assertThat(mTunerResourceManagerService.getResourceIdFromHandle(frontendHandle[0]))
.isEqualTo(infos[1].getId());
assertThat(mTunerResourceManagerService.getFrontendResource(infos[0].getId())
@@ -511,12 +471,8 @@ public class TunerResourceManagerServiceTest {
TunerFrontendRequest request =
new TunerFrontendRequest(clientId[0] /*clientId*/, FrontendSettings.TYPE_DVBT);
int[] frontendHandle = new int[1];
try {
assertThat(mTunerResourceManagerService
.requestFrontendInternal(request, frontendHandle)).isTrue();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
assertThat(mTunerResourceManagerService
.requestFrontendInternal(request, frontendHandle)).isTrue();
int frontendId = mTunerResourceManagerService.getResourceIdFromHandle(frontendHandle[0]);
assertThat(frontendId).isEqualTo(infos[0].getId());
assertThat(mTunerResourceManagerService
@@ -533,6 +489,99 @@ public class TunerResourceManagerServiceTest {
.getClientProfile(clientId[0]).getInUseFrontendIds().size()).isEqualTo(0);
}
@Test
public void requestCasTest_NoCasAvailable_RequestWithHigherPriority() {
// Register clients
ResourceClientProfile[] profiles = new ResourceClientProfile[2];
profiles[0] = new ResourceClientProfile("0" /*sessionId*/,
TvInputService.PRIORITY_HINT_USE_CASE_TYPE_PLAYBACK);
profiles[1] = new ResourceClientProfile("1" /*sessionId*/,
TvInputService.PRIORITY_HINT_USE_CASE_TYPE_PLAYBACK);
int[] clientPriorities = {100, 500};
int[] clientId0 = new int[1];
int[] clientId1 = new int[1];
TestResourcesReclaimListener listener = new TestResourcesReclaimListener();
mTunerResourceManagerService.registerClientProfileInternal(
profiles[0], listener, clientId0);
assertThat(clientId0[0]).isNotEqualTo(TunerResourceManagerService.INVALID_CLIENT_ID);
mTunerResourceManagerService.getClientProfile(clientId0[0])
.setPriority(clientPriorities[0]);
mTunerResourceManagerService.registerClientProfileInternal(
profiles[1], new TestResourcesReclaimListener(), clientId1);
assertThat(clientId1[0]).isNotEqualTo(TunerResourceManagerService.INVALID_CLIENT_ID);
mTunerResourceManagerService.getClientProfile(clientId1[0])
.setPriority(clientPriorities[1]);
// Init cas resources.
mTunerResourceManagerService.updateCasInfoInternal(1 /*casSystemId*/, 2 /*maxSessionNum*/);
CasSessionRequest request = new CasSessionRequest(clientId0[0], 1 /*casSystemId*/);
int[] casSessionHandle = new int[1];
// Request for 2 cas sessions.
assertThat(mTunerResourceManagerService
.requestCasSessionInternal(request, casSessionHandle)).isTrue();
assertThat(mTunerResourceManagerService
.requestCasSessionInternal(request, casSessionHandle)).isTrue();
assertThat(mTunerResourceManagerService.getResourceIdFromHandle(casSessionHandle[0]))
.isEqualTo(1);
assertThat(mTunerResourceManagerService.getClientProfile(clientId0[0])
.getInUseCasSystemId()).isEqualTo(1);
assertThat(mTunerResourceManagerService.getCasResource(1)
.getOwnerClientIds()).isEqualTo(new HashSet<Integer>(Arrays.asList(clientId0[0])));
assertThat(mTunerResourceManagerService.getCasResource(1).isFullyUsed()).isTrue();
request = new CasSessionRequest(clientId1[0], 1);
assertThat(mTunerResourceManagerService
.requestCasSessionInternal(request, casSessionHandle)).isTrue();
assertThat(mTunerResourceManagerService.getResourceIdFromHandle(casSessionHandle[0]))
.isEqualTo(1);
assertThat(mTunerResourceManagerService.getClientProfile(clientId1[0])
.getInUseCasSystemId()).isEqualTo(1);
assertThat(mTunerResourceManagerService.getClientProfile(clientId0[0])
.getInUseCasSystemId()).isEqualTo(ClientProfile.INVALID_RESOURCE_ID);
assertThat(mTunerResourceManagerService.getCasResource(1)
.getOwnerClientIds()).isEqualTo(new HashSet<Integer>(Arrays.asList(clientId1[0])));
assertThat(mTunerResourceManagerService.getCasResource(1).isFullyUsed()).isFalse();
assertThat(listener.isRelaimed()).isTrue();
}
@Test
public void releaseCasTest() {
// Register clients
ResourceClientProfile[] profiles = new ResourceClientProfile[1];
profiles[0] = new ResourceClientProfile("0" /*sessionId*/,
TvInputService.PRIORITY_HINT_USE_CASE_TYPE_PLAYBACK);
int[] clientId = new int[1];
TestResourcesReclaimListener listener = new TestResourcesReclaimListener();
mTunerResourceManagerService.registerClientProfileInternal(profiles[0], listener, clientId);
assertThat(clientId[0]).isNotEqualTo(TunerResourceManagerService.INVALID_CLIENT_ID);
// Init cas resources.
mTunerResourceManagerService.updateCasInfoInternal(1 /*casSystemId*/, 2 /*maxSessionNum*/);
CasSessionRequest request = new CasSessionRequest(clientId[0], 1 /*casSystemId*/);
int[] casSessionHandle = new int[1];
// Request for 1 cas sessions.
assertThat(mTunerResourceManagerService
.requestCasSessionInternal(request, casSessionHandle)).isTrue();
assertThat(mTunerResourceManagerService.getResourceIdFromHandle(casSessionHandle[0]))
.isEqualTo(1);
assertThat(mTunerResourceManagerService.getClientProfile(clientId[0])
.getInUseCasSystemId()).isEqualTo(1);
assertThat(mTunerResourceManagerService.getCasResource(1)
.getOwnerClientIds()).isEqualTo(new HashSet<Integer>(Arrays.asList(clientId[0])));
assertThat(mTunerResourceManagerService.getCasResource(1).isFullyUsed()).isFalse();
// Release cas
mTunerResourceManagerService.releaseCasSessionInternal(mTunerResourceManagerService
.getCasResource(1), clientId[0]);
assertThat(mTunerResourceManagerService.getClientProfile(clientId[0])
.getInUseCasSystemId()).isEqualTo(ClientProfile.INVALID_RESOURCE_ID);
assertThat(mTunerResourceManagerService.getCasResource(1).isFullyUsed()).isFalse();
assertThat(mTunerResourceManagerService.getCasResource(1)
.getOwnerClientIds()).isEmpty();
}
@Test
public void requestLnbTest_NoLnbAvailable_RequestWithHigherPriority() {
// Register clients
@@ -562,24 +611,16 @@ public class TunerResourceManagerServiceTest {
TunerLnbRequest request = new TunerLnbRequest(clientId0[0]);
int[] lnbHandle = new int[1];
try {
assertThat(mTunerResourceManagerService
.requestLnbInternal(request, lnbHandle)).isTrue();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
assertThat(mTunerResourceManagerService
.requestLnbInternal(request, lnbHandle)).isTrue();
assertThat(mTunerResourceManagerService.getResourceIdFromHandle(lnbHandle[0]))
.isEqualTo(lnbIds[0]);
assertThat(mTunerResourceManagerService.getClientProfile(clientId0[0])
.getInUseLnbIds()).isEqualTo(new HashSet<Integer>(Arrays.asList(lnbIds[0])));
request = new TunerLnbRequest(clientId1[0]);
try {
assertThat(mTunerResourceManagerService
.requestLnbInternal(request, lnbHandle)).isTrue();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
assertThat(mTunerResourceManagerService
.requestLnbInternal(request, lnbHandle)).isTrue();
assertThat(mTunerResourceManagerService.getResourceIdFromHandle(lnbHandle[0]))
.isEqualTo(lnbIds[0]);
assertThat(mTunerResourceManagerService.getLnbResource(lnbIds[0])
@@ -608,12 +649,8 @@ public class TunerResourceManagerServiceTest {
TunerLnbRequest request = new TunerLnbRequest(clientId[0]);
int[] lnbHandle = new int[1];
try {
assertThat(mTunerResourceManagerService
.requestLnbInternal(request, lnbHandle)).isTrue();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
assertThat(mTunerResourceManagerService
.requestLnbInternal(request, lnbHandle)).isTrue();
int lnbId = mTunerResourceManagerService.getResourceIdFromHandle(lnbHandle[0]);
assertThat(lnbId).isEqualTo(lnbIds[0]);
@@ -647,12 +684,8 @@ public class TunerResourceManagerServiceTest {
TunerFrontendRequest request =
new TunerFrontendRequest(clientId[0] /*clientId*/, FrontendSettings.TYPE_DVBT);
int[] frontendHandle = new int[1];
try {
assertThat(mTunerResourceManagerService
.requestFrontendInternal(request, frontendHandle)).isTrue();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
assertThat(mTunerResourceManagerService
.requestFrontendInternal(request, frontendHandle)).isTrue();
assertThat(mTunerResourceManagerService.getResourceIdFromHandle(frontendHandle[0]))
.isEqualTo(infos[0].getId());
assertThat(mTunerResourceManagerService.getFrontendResource(infos[0].getId())