Merge changes from topic "trm-impl-rvc" into rvc-dev
* changes: Fix issues in register/unregister client API implementation Add a TRM use case priority hints info object Add requestFrontend implementation in TunerResourceManager Implement TRM setFrontendInfoList logic with unit tests
This commit is contained in:
@@ -78,7 +78,8 @@ public final class ResourceClientProfile implements Parcelable {
|
|||||||
* {@link android.media.tv.TvInputService.PRIORITY_HINT_USE_CASE_TYPE_LIVE}
|
* {@link android.media.tv.TvInputService.PRIORITY_HINT_USE_CASE_TYPE_LIVE}
|
||||||
* {@link android.media.tv.TvInputService.PRIORITY_HINT_USE_CASE_TYPE_RECORD}.
|
* {@link android.media.tv.TvInputService.PRIORITY_HINT_USE_CASE_TYPE_RECORD}.
|
||||||
* New [use case : priority value] pair can be defined in the manifest by the
|
* New [use case : priority value] pair can be defined in the manifest by the
|
||||||
* OEM. Any undefined use case would cause IllegalArgumentException.
|
* OEM. The id of the useCaseVendor should be passed through this parameter. Any
|
||||||
|
* undefined use case would cause IllegalArgumentException.
|
||||||
*/
|
*/
|
||||||
public ResourceClientProfile(@NonNull String tvInputSessionId,
|
public ResourceClientProfile(@NonNull String tvInputSessionId,
|
||||||
int useCase) {
|
int useCase) {
|
||||||
|
|||||||
@@ -13,9 +13,11 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.android.server.tv.tunerresourcemanager;
|
package com.android.server.tv.tunerresourcemanager;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A client profile object used by the Tuner Resource Manager to record the registered clients'
|
* A client profile object used by the Tuner Resource Manager to record the registered clients'
|
||||||
* information.
|
* information.
|
||||||
@@ -23,12 +25,14 @@ package com.android.server.tv.tunerresourcemanager;
|
|||||||
* @hide
|
* @hide
|
||||||
*/
|
*/
|
||||||
public final class ClientProfile {
|
public final class ClientProfile {
|
||||||
|
|
||||||
public static final int INVALID_GROUP_ID = -1;
|
public static final int INVALID_GROUP_ID = -1;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Client id sent to the client when registering with
|
* Client id sent to the client when registering with
|
||||||
* {@link #registerClientProfile(ResourceClientProfile, TunerResourceManagerCallback, int[])}
|
* {@link #registerClientProfile(ResourceClientProfile, TunerResourceManagerCallback, int[])}
|
||||||
*/
|
*/
|
||||||
private final int mClientId;
|
private final int mId;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* see {@link ResourceClientProfile}
|
* see {@link ResourceClientProfile}
|
||||||
@@ -41,7 +45,7 @@ public final class ClientProfile {
|
|||||||
private final int mUseCase;
|
private final int mUseCase;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Process id queried from {@link TvInputManager#}
|
* Process id queried from {@link TvInputManager#getPid(String)}.
|
||||||
*/
|
*/
|
||||||
private final int mProcessId;
|
private final int mProcessId;
|
||||||
|
|
||||||
@@ -58,6 +62,11 @@ public final class ClientProfile {
|
|||||||
*/
|
*/
|
||||||
private int mNiceValue;
|
private int mNiceValue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List of the frontend ids that are used by the current client.
|
||||||
|
*/
|
||||||
|
private List<Integer> mUsingFrontendIds = new ArrayList<>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Optional arbitrary priority value given by the client.
|
* Optional arbitrary priority value given by the client.
|
||||||
*
|
*
|
||||||
@@ -66,18 +75,15 @@ public final class ClientProfile {
|
|||||||
*/
|
*/
|
||||||
private int mPriority;
|
private int mPriority;
|
||||||
|
|
||||||
private ClientProfile(ClientProfileBuilder builder) {
|
private ClientProfile(Builder builder) {
|
||||||
this.mClientId = builder.mClientId;
|
this.mId = builder.mId;
|
||||||
this.mTvInputSessionId = builder.mTvInputSessionId;
|
this.mTvInputSessionId = builder.mTvInputSessionId;
|
||||||
this.mUseCase = builder.mUseCase;
|
this.mUseCase = builder.mUseCase;
|
||||||
this.mProcessId = builder.mProcessId;
|
this.mProcessId = builder.mProcessId;
|
||||||
this.mGroupId = builder.mGroupId;
|
|
||||||
this.mNiceValue = builder.mNiceValue;
|
|
||||||
this.mPriority = builder.mPriority;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getClientId() {
|
public int getId() {
|
||||||
return mClientId;
|
return mId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getTvInputSessionId() {
|
public String getTvInputSessionId() {
|
||||||
@@ -116,26 +122,47 @@ public final class ClientProfile {
|
|||||||
mNiceValue = niceValue;
|
mNiceValue = niceValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set when the client starts to use a frontend.
|
||||||
|
*
|
||||||
|
* @param frontendId being used.
|
||||||
|
*/
|
||||||
|
public void useFrontend(int frontendId) {
|
||||||
|
mUsingFrontendIds.add(frontendId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Integer> getInUseFrontendIds() {
|
||||||
|
return mUsingFrontendIds;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when the client released a frontend.
|
||||||
|
*
|
||||||
|
* <p>This could happen when client resource reclaimed.
|
||||||
|
*
|
||||||
|
* @param frontendId being released.
|
||||||
|
*/
|
||||||
|
public void releaseFrontend(int frontendId) {
|
||||||
|
mUsingFrontendIds.remove(frontendId);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "ClientProfile: " + this.mClientId + ", " + this.mTvInputSessionId + ", "
|
return "ClientProfile[id=" + this.mId + ", tvInputSessionId=" + this.mTvInputSessionId
|
||||||
+ this.mUseCase + ", " + this.mProcessId;
|
+ ", useCase=" + this.mUseCase + ", processId=" + this.mProcessId + "]";
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Builder class for {@link ClientProfile}.
|
* Builder class for {@link ClientProfile}.
|
||||||
*/
|
*/
|
||||||
public static class ClientProfileBuilder {
|
public static class Builder {
|
||||||
private final int mClientId;
|
private final int mId;
|
||||||
private String mTvInputSessionId;
|
private String mTvInputSessionId;
|
||||||
private int mUseCase;
|
private int mUseCase;
|
||||||
private int mProcessId;
|
private int mProcessId;
|
||||||
private int mGroupId;
|
|
||||||
private int mNiceValue;
|
|
||||||
private int mPriority;
|
|
||||||
|
|
||||||
ClientProfileBuilder(int clientId) {
|
Builder(int id) {
|
||||||
this.mClientId = clientId;
|
this.mId = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -143,7 +170,7 @@ public final class ClientProfile {
|
|||||||
*
|
*
|
||||||
* @param useCase the useCase of the client.
|
* @param useCase the useCase of the client.
|
||||||
*/
|
*/
|
||||||
public ClientProfileBuilder useCase(int useCase) {
|
public Builder useCase(int useCase) {
|
||||||
this.mUseCase = useCase;
|
this.mUseCase = useCase;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@@ -153,7 +180,7 @@ public final class ClientProfile {
|
|||||||
*
|
*
|
||||||
* @param tvInputSessionId the id of the tv input session.
|
* @param tvInputSessionId the id of the tv input session.
|
||||||
*/
|
*/
|
||||||
public ClientProfileBuilder tvInputSessionId(String tvInputSessionId) {
|
public Builder tvInputSessionId(String tvInputSessionId) {
|
||||||
this.mTvInputSessionId = tvInputSessionId;
|
this.mTvInputSessionId = tvInputSessionId;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@@ -163,42 +190,11 @@ public final class ClientProfile {
|
|||||||
*
|
*
|
||||||
* @param processId the id of process.
|
* @param processId the id of process.
|
||||||
*/
|
*/
|
||||||
public ClientProfileBuilder processId(int processId) {
|
public Builder processId(int processId) {
|
||||||
this.mProcessId = processId;
|
this.mProcessId = processId;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Builder for {@link ClientProfile}.
|
|
||||||
*
|
|
||||||
* @param groupId the id of the group that shares the same resource.
|
|
||||||
*/
|
|
||||||
public ClientProfileBuilder groupId(int groupId) {
|
|
||||||
this.mGroupId = groupId;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Builder for {@link ClientProfile}.
|
|
||||||
*
|
|
||||||
* @param niceValue the nice value of the client.
|
|
||||||
*/
|
|
||||||
public ClientProfileBuilder niceValue(int niceValue) {
|
|
||||||
this.mNiceValue = niceValue;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Builder for {@link ClientProfile}.
|
|
||||||
*
|
|
||||||
* @param priority the priority value of the client.
|
|
||||||
*/
|
|
||||||
public ClientProfileBuilder priority(int priority) {
|
|
||||||
this.mPriority = priority;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Build a {@link ClientProfile}.
|
* Build a {@link ClientProfile}.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -0,0 +1,204 @@
|
|||||||
|
/*
|
||||||
|
* 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 android.annotation.Nullable;
|
||||||
|
import android.media.tv.tuner.frontend.FrontendSettings.Type;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A frontend resource object used by the Tuner Resource Manager to record the tuner frontend
|
||||||
|
* information.
|
||||||
|
*
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
public final class FrontendResource {
|
||||||
|
public static final int INVALID_OWNER_ID = -1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Id of the current frontend. Should not be changed and should be aligned with the driver level
|
||||||
|
* implementation.
|
||||||
|
*/
|
||||||
|
private final int mId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* see {@link android.media.tv.tuner.frontend.FrontendSettings.Type}
|
||||||
|
*/
|
||||||
|
@Type private final int mType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The exclusive group id of the FE. FEs under the same id can't be used at the same time.
|
||||||
|
*/
|
||||||
|
private final int mExclusiveGroupId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An array to save all the FE ids under the same exclisive group.
|
||||||
|
*/
|
||||||
|
private List<Integer> mExclusiveGroupMemberFeIds = new ArrayList<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If the current resource is in use. Once resources under the same exclusive group id is in use
|
||||||
|
* all other resources in the same group would be considered in use.
|
||||||
|
*/
|
||||||
|
private boolean mIsInUse;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The owner client's id if this resource is occupied. Owner of the resource under the same
|
||||||
|
* exclusive group id would be considered as the whole group's owner.
|
||||||
|
*/
|
||||||
|
private int mOwnerClientId = INVALID_OWNER_ID;
|
||||||
|
|
||||||
|
private FrontendResource(Builder builder) {
|
||||||
|
this.mId = builder.mId;
|
||||||
|
this.mType = builder.mType;
|
||||||
|
this.mExclusiveGroupId = builder.mExclusiveGroupId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getId() {
|
||||||
|
return mId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getType() {
|
||||||
|
return mType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getExclusiveGroupId() {
|
||||||
|
return mExclusiveGroupId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Integer> getExclusiveGroupMemberFeIds() {
|
||||||
|
return mExclusiveGroupMemberFeIds;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add one id into the exclusive group member id list.
|
||||||
|
*
|
||||||
|
* @param id the id to be added.
|
||||||
|
*/
|
||||||
|
public void addExclusiveGroupMemberFeId(int id) {
|
||||||
|
mExclusiveGroupMemberFeIds.add(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add one id list to the exclusive group member id list.
|
||||||
|
*
|
||||||
|
* @param ids the id list to be added.
|
||||||
|
*/
|
||||||
|
public void addExclusiveGroupMemberFeId(List<Integer> ids) {
|
||||||
|
mExclusiveGroupMemberFeIds.addAll(ids);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove one id from the exclusive group member id list.
|
||||||
|
*
|
||||||
|
* @param id the id to be removed.
|
||||||
|
*/
|
||||||
|
public void removeExclusiveGroupMemberFeId(int id) {
|
||||||
|
mExclusiveGroupMemberFeIds.remove(new Integer(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isInUse() {
|
||||||
|
return mIsInUse;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getOwnerClientId() {
|
||||||
|
return mOwnerClientId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set an owner client on the resource.
|
||||||
|
*
|
||||||
|
* @param ownerClientId the id of the owner client.
|
||||||
|
*/
|
||||||
|
public void setOwner(int ownerClientId) {
|
||||||
|
mIsInUse = true;
|
||||||
|
mOwnerClientId = ownerClientId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove an owner client from the resource.
|
||||||
|
*/
|
||||||
|
public void removeOwner() {
|
||||||
|
mIsInUse = false;
|
||||||
|
mOwnerClientId = INVALID_OWNER_ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "FrontendResource[id=" + this.mId + ", type=" + this.mType
|
||||||
|
+ ", exclusiveGId=" + this.mExclusiveGroupId + ", exclusiveGMemeberIds="
|
||||||
|
+ Arrays.toString(this.mExclusiveGroupMemberFeIds.toArray())
|
||||||
|
+ ", isInUse=" + this.mIsInUse + ", ownerClientId=" + this.mOwnerClientId + "]";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(@Nullable Object o) {
|
||||||
|
if (o instanceof FrontendResource) {
|
||||||
|
FrontendResource fe = (FrontendResource) o;
|
||||||
|
return mId == fe.getId() && mType == fe.getType()
|
||||||
|
&& mExclusiveGroupId == fe.getExclusiveGroupId()
|
||||||
|
&& mExclusiveGroupMemberFeIds.equals(fe.getExclusiveGroupMemberFeIds())
|
||||||
|
&& mIsInUse == fe.isInUse() && mOwnerClientId == fe.getOwnerClientId();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builder class for {@link FrontendResource}.
|
||||||
|
*/
|
||||||
|
public static class Builder {
|
||||||
|
private final int mId;
|
||||||
|
@Type private int mType;
|
||||||
|
private int mExclusiveGroupId;
|
||||||
|
|
||||||
|
Builder(int id) {
|
||||||
|
this.mId = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builder for {@link FrontendResource}.
|
||||||
|
*
|
||||||
|
* @param type the type of the frontend. See {@link Type}
|
||||||
|
*/
|
||||||
|
public Builder type(@Type int type) {
|
||||||
|
this.mType = type;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builder for {@link FrontendResource}.
|
||||||
|
*
|
||||||
|
* @param exclusiveGroupId the id of exclusive group.
|
||||||
|
*/
|
||||||
|
public Builder exclusiveGroupId(int exclusiveGroupId) {
|
||||||
|
this.mExclusiveGroupId = exclusiveGroupId;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build a {@link FrontendResource}.
|
||||||
|
*
|
||||||
|
* @return {@link FrontendResource}.
|
||||||
|
*/
|
||||||
|
public FrontendResource build() {
|
||||||
|
FrontendResource frontendResource = new FrontendResource(this);
|
||||||
|
return frontendResource;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -28,11 +28,13 @@ import android.media.tv.tunerresourcemanager.TunerFrontendInfo;
|
|||||||
import android.media.tv.tunerresourcemanager.TunerFrontendRequest;
|
import android.media.tv.tunerresourcemanager.TunerFrontendRequest;
|
||||||
import android.media.tv.tunerresourcemanager.TunerLnbRequest;
|
import android.media.tv.tunerresourcemanager.TunerLnbRequest;
|
||||||
import android.media.tv.tunerresourcemanager.TunerResourceManager;
|
import android.media.tv.tunerresourcemanager.TunerResourceManager;
|
||||||
|
import android.os.Binder;
|
||||||
import android.os.RemoteException;
|
import android.os.RemoteException;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.util.Slog;
|
import android.util.Slog;
|
||||||
import android.util.SparseArray;
|
import android.util.SparseArray;
|
||||||
|
|
||||||
|
import com.android.internal.annotations.VisibleForTesting;
|
||||||
import com.android.server.SystemService;
|
import com.android.server.SystemService;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -47,13 +49,27 @@ public class TunerResourceManagerService extends SystemService {
|
|||||||
private static final String TAG = "TunerResourceManagerService";
|
private static final String TAG = "TunerResourceManagerService";
|
||||||
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
|
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
|
||||||
|
|
||||||
private SparseArray<ClientProfile> mClientProfiles = new SparseArray<>();
|
public static final int INVALID_CLIENT_ID = -1;
|
||||||
private SparseArray<IResourcesReclaimListener> mListeners = new SparseArray<>();
|
private static final int MAX_CLIENT_PRIORITY = 1000;
|
||||||
private int mNextUnusedFrontendId = 0;
|
|
||||||
private List<Integer> mReleasedClientId = new ArrayList<Integer>();
|
// Array of the registered client profiles
|
||||||
|
@VisibleForTesting private SparseArray<ClientProfile> mClientProfiles = new SparseArray<>();
|
||||||
|
private int mNextUnusedClientId = 0;
|
||||||
|
private List<Integer> mRegisteredClientIds = new ArrayList<Integer>();
|
||||||
|
|
||||||
|
// Array of the current available frontend resources
|
||||||
|
@VisibleForTesting
|
||||||
|
private SparseArray<FrontendResource> mFrontendResources = new SparseArray<>();
|
||||||
|
// Array of the current available frontend ids
|
||||||
private List<Integer> mAvailableFrontendIds = new ArrayList<Integer>();
|
private List<Integer> mAvailableFrontendIds = new ArrayList<Integer>();
|
||||||
|
|
||||||
|
private SparseArray<IResourcesReclaimListener> mListeners = new SparseArray<>();
|
||||||
|
|
||||||
private TvInputManager mManager;
|
private TvInputManager mManager;
|
||||||
|
private UseCasePriorityHints mPriorityCongfig = new UseCasePriorityHints();
|
||||||
|
|
||||||
|
// Used to synchronize the access to the service.
|
||||||
|
private final Object mLock = new Object();
|
||||||
|
|
||||||
public TunerResourceManagerService(@Nullable Context context) {
|
public TunerResourceManagerService(@Nullable Context context) {
|
||||||
super(context);
|
super(context);
|
||||||
@@ -61,97 +77,78 @@ public class TunerResourceManagerService extends SystemService {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onStart() {
|
public void onStart() {
|
||||||
|
onStart(false /*isForTesting*/);
|
||||||
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
protected void onStart(boolean isForTesting) {
|
||||||
|
if (!isForTesting) {
|
||||||
publishBinderService(Context.TV_TUNER_RESOURCE_MGR_SERVICE, new BinderService());
|
publishBinderService(Context.TV_TUNER_RESOURCE_MGR_SERVICE, new BinderService());
|
||||||
mManager = (TvInputManager) getContext()
|
}
|
||||||
.getSystemService(Context.TV_INPUT_SERVICE);
|
mManager = (TvInputManager) getContext().getSystemService(Context.TV_INPUT_SERVICE);
|
||||||
|
mPriorityCongfig.parse();
|
||||||
}
|
}
|
||||||
|
|
||||||
private final class BinderService extends ITunerResourceManager.Stub {
|
private final class BinderService extends ITunerResourceManager.Stub {
|
||||||
@Override
|
@Override
|
||||||
public void registerClientProfile(@NonNull ResourceClientProfile profile,
|
public void registerClientProfile(@NonNull ResourceClientProfile profile,
|
||||||
@NonNull IResourcesReclaimListener listener,
|
@NonNull IResourcesReclaimListener listener, @NonNull int[] clientId)
|
||||||
@NonNull int[] clientId) {
|
throws RemoteException {
|
||||||
if (DEBUG) {
|
enforceAccessPermission();
|
||||||
Slog.d(TAG, "registerClientProfile(clientProfile=" + profile + ")");
|
if (profile == null) {
|
||||||
|
throw new RemoteException("ResourceClientProfile can't be null");
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO tell if the client already exists
|
if (clientId == null) {
|
||||||
if (mReleasedClientId.isEmpty()) {
|
throw new RemoteException("clientId can't be null!");
|
||||||
clientId[0] = mNextUnusedFrontendId++;
|
|
||||||
} else {
|
|
||||||
clientId[0] = mReleasedClientId.get(0);
|
|
||||||
mReleasedClientId.remove(0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mManager == null) {
|
if (!mPriorityCongfig.isDefinedUseCase(profile.getUseCase())) {
|
||||||
Slog.e(TAG, "TvInputManager is null. Can't register client profile.");
|
throw new RemoteException("Use undefined client use case:" + profile.getUseCase());
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int callingPid = mManager.getClientPid(profile.getTvInputSessionId());
|
synchronized (mLock) {
|
||||||
|
registerClientProfileInternal(profile, listener, clientId);
|
||||||
ClientProfile clientProfile = new ClientProfile.ClientProfileBuilder(
|
}
|
||||||
clientId[0])
|
|
||||||
.tvInputSessionId(profile.getTvInputSessionId())
|
|
||||||
.useCase(profile.getUseCase())
|
|
||||||
.processId(callingPid)
|
|
||||||
.build();
|
|
||||||
mClientProfiles.append(clientId[0], clientProfile);
|
|
||||||
mListeners.append(clientId[0], listener);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void unregisterClientProfile(int clientId) {
|
public void unregisterClientProfile(int clientId) throws RemoteException {
|
||||||
if (DEBUG) {
|
enforceAccessPermission();
|
||||||
Slog.d(TAG, "unregisterClientProfile(clientId=" + clientId + ")");
|
synchronized (mLock) {
|
||||||
|
if (!checkClientExists(clientId)) {
|
||||||
|
Slog.e(TAG, "Unregistering non exists client:" + clientId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
unregisterClientProfileInternal(clientId);
|
||||||
}
|
}
|
||||||
|
|
||||||
mClientProfiles.remove(clientId);
|
|
||||||
mListeners.remove(clientId);
|
|
||||||
mReleasedClientId.add(clientId);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean updateClientPriority(int clientId, int priority, int niceValue) {
|
public boolean updateClientPriority(int clientId, int priority, int niceValue) {
|
||||||
if (DEBUG) {
|
enforceAccessPermission();
|
||||||
Slog.d(TAG, "updateClientPriority(clientId=" + clientId
|
synchronized (mLock) {
|
||||||
+ ", priority=" + priority + ", niceValue=" + niceValue + ")");
|
return updateClientPriorityInternal(clientId, priority, niceValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
ClientProfile profile = mClientProfiles.get(clientId);
|
|
||||||
if (profile == null) {
|
|
||||||
Slog.e(TAG, "Can not find client profile with id " + clientId
|
|
||||||
+ " when trying to update the client priority.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
profile.setPriority(priority);
|
|
||||||
profile.setNiceValue(niceValue);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setFrontendInfoList(@NonNull TunerFrontendInfo[] infos)
|
public void setFrontendInfoList(@NonNull TunerFrontendInfo[] infos) throws RemoteException {
|
||||||
throws RemoteException {
|
enforceAccessPermission();
|
||||||
if (infos == null || infos.length == 0) {
|
if (infos == null) {
|
||||||
Slog.d(TAG, "Can't update with empty frontend info");
|
throw new RemoteException("TunerFrontendInfo can't be null");
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (DEBUG) {
|
|
||||||
Slog.d(TAG, "updateFrontendInfo:");
|
|
||||||
for (int i = 0; i < infos.length; i++) {
|
|
||||||
Slog.d(TAG, infos[i].toString());
|
|
||||||
}
|
}
|
||||||
|
synchronized (mLock) {
|
||||||
|
setFrontendInfoListInternal(infos);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void updateCasInfo(int casSystemId, int maxSessionNum) {
|
public void updateCasInfo(int casSystemId, int maxSessionNum) {
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
Slog.d(TAG, "updateCasInfo(casSystemId="
|
Slog.d(TAG,
|
||||||
+ casSystemId + ", maxSessionNum=" + maxSessionNum + ")");
|
"updateCasInfo(casSystemId=" + casSystemId
|
||||||
|
+ ", maxSessionNum=" + maxSessionNum + ")");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -167,48 +164,29 @@ public class TunerResourceManagerService extends SystemService {
|
|||||||
@Override
|
@Override
|
||||||
public boolean requestFrontend(@NonNull TunerFrontendRequest request,
|
public boolean requestFrontend(@NonNull TunerFrontendRequest request,
|
||||||
@NonNull int[] frontendId) throws RemoteException {
|
@NonNull int[] frontendId) throws RemoteException {
|
||||||
if (DEBUG) {
|
enforceAccessPermission();
|
||||||
Slog.d(TAG, "requestFrontend(request=" + request + ")");
|
if (frontendId == null) {
|
||||||
|
throw new RemoteException("frontendId can't be null");
|
||||||
}
|
}
|
||||||
|
synchronized (mLock) {
|
||||||
frontendId[0] = TunerResourceManager.INVALID_FRONTEND_ID;
|
try {
|
||||||
|
return requestFrontendInternal(request, frontendId);
|
||||||
if (getContext() == null) {
|
} catch (RemoteException e) {
|
||||||
Slog.e(TAG, "Can not find context when requesting frontend");
|
throw e.rethrowFromSystemServer();
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mClientProfiles.get(request.getClientId()) == null) {
|
|
||||||
Slog.e(TAG, "Request from unregistered client. Id: "
|
|
||||||
+ request.getClientId());
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
String sessionId = mClientProfiles.get(request.getClientId())
|
|
||||||
.getTvInputSessionId();
|
|
||||||
|
|
||||||
if (DEBUG) {
|
|
||||||
Slog.d(TAG, "session Id:" + sessionId + ")");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (DEBUG) {
|
|
||||||
Slog.d(TAG, "No available Frontend found.");
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void shareFrontend(int selfClientId, int targetClientId) {
|
public void shareFrontend(int selfClientId, int targetClientId) {
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
Slog.d(TAG, "shareFrontend from "
|
Slog.d(TAG, "shareFrontend from " + selfClientId + " with " + targetClientId);
|
||||||
+ selfClientId + " with " + targetClientId);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean requestCasSession(@NonNull CasSessionRequest request,
|
public boolean requestCasSession(
|
||||||
@NonNull int[] sessionResourceId) {
|
@NonNull CasSessionRequest request, @NonNull int[] sessionResourceId) {
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
Slog.d(TAG, "requestCasSession(request=" + request + ")");
|
Slog.d(TAG, "requestCasSession(request=" + request + ")");
|
||||||
}
|
}
|
||||||
@@ -246,13 +224,284 @@ public class TunerResourceManagerService extends SystemService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isHigherPriority(ResourceClientProfile challengerProfile,
|
public boolean isHigherPriority(
|
||||||
ResourceClientProfile holderProfile) {
|
ResourceClientProfile challengerProfile, ResourceClientProfile holderProfile) {
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
Slog.d(TAG, "isHigherPriority(challengerProfile=" + challengerProfile
|
Slog.d(TAG,
|
||||||
|
"isHigherPriority(challengerProfile=" + challengerProfile
|
||||||
+ ", holderProfile=" + challengerProfile + ")");
|
+ ", holderProfile=" + challengerProfile + ")");
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
protected void registerClientProfileInternal(ResourceClientProfile profile,
|
||||||
|
IResourcesReclaimListener listener, int[] clientId) {
|
||||||
|
if (DEBUG) {
|
||||||
|
Slog.d(TAG, "registerClientProfile(clientProfile=" + profile + ")");
|
||||||
|
}
|
||||||
|
|
||||||
|
clientId[0] = INVALID_CLIENT_ID;
|
||||||
|
if (mManager == null) {
|
||||||
|
Slog.e(TAG, "TvInputManager is null. Can't register client profile.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// TODO tell if the client already exists
|
||||||
|
clientId[0] = mNextUnusedClientId++;
|
||||||
|
|
||||||
|
int pid = profile.getTvInputSessionId() == null
|
||||||
|
? Binder.getCallingPid() /*callingPid*/
|
||||||
|
: mManager.getClientPid(profile.getTvInputSessionId()); /*tvAppId*/
|
||||||
|
|
||||||
|
ClientProfile clientProfile = new ClientProfile.Builder(clientId[0])
|
||||||
|
.tvInputSessionId(profile.getTvInputSessionId())
|
||||||
|
.useCase(profile.getUseCase())
|
||||||
|
.processId(pid)
|
||||||
|
.build();
|
||||||
|
clientProfile.setPriority(getClientPriority(profile.getUseCase(), pid));
|
||||||
|
|
||||||
|
mClientProfiles.append(clientId[0], clientProfile);
|
||||||
|
mListeners.append(clientId[0], listener);
|
||||||
|
mRegisteredClientIds.add(clientId[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
protected void unregisterClientProfileInternal(int clientId) {
|
||||||
|
if (DEBUG) {
|
||||||
|
Slog.d(TAG, "unregisterClientProfile(clientId=" + clientId + ")");
|
||||||
|
}
|
||||||
|
for (int id : getClientProfile(clientId).getInUseFrontendIds()) {
|
||||||
|
getFrontendResource(id).removeOwner();
|
||||||
|
for (int groupMemberId : getFrontendResource(id).getExclusiveGroupMemberFeIds()) {
|
||||||
|
getFrontendResource(groupMemberId).removeOwner();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mClientProfiles.remove(clientId);
|
||||||
|
mListeners.remove(clientId);
|
||||||
|
mRegisteredClientIds.remove(clientId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
protected boolean updateClientPriorityInternal(int clientId, int priority, int niceValue) {
|
||||||
|
if (DEBUG) {
|
||||||
|
Slog.d(TAG,
|
||||||
|
"updateClientPriority(clientId=" + clientId + ", priority=" + priority
|
||||||
|
+ ", niceValue=" + niceValue + ")");
|
||||||
|
}
|
||||||
|
|
||||||
|
ClientProfile profile = getClientProfile(clientId);
|
||||||
|
if (profile == null) {
|
||||||
|
Slog.e(TAG,
|
||||||
|
"Can not find client profile with id " + clientId
|
||||||
|
+ " when trying to update the client priority.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
profile.setPriority(priority);
|
||||||
|
profile.setNiceValue(niceValue);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
protected void setFrontendInfoListInternal(TunerFrontendInfo[] infos) {
|
||||||
|
if (DEBUG) {
|
||||||
|
Slog.d(TAG, "updateFrontendInfo:");
|
||||||
|
for (int i = 0; i < infos.length; i++) {
|
||||||
|
Slog.d(TAG, infos[i].toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// An arrayList to record the frontends pending on updating. Ids will be removed
|
||||||
|
// from this list once its updating finished. Any frontend left in this list when all
|
||||||
|
// the updates are done will be removed from mAvailableFrontendIds and
|
||||||
|
// mFrontendResources.
|
||||||
|
List<Integer> updatingFrontendIds = new ArrayList<>(mAvailableFrontendIds);
|
||||||
|
|
||||||
|
// Update frontendResources sparse array and other mappings accordingly
|
||||||
|
for (int i = 0; i < infos.length; i++) {
|
||||||
|
if (getFrontendResource(infos[i].getId()) != null) {
|
||||||
|
if (DEBUG) {
|
||||||
|
Slog.d(TAG, "Frontend id=" + infos[i].getId() + "exists.");
|
||||||
|
}
|
||||||
|
updatingFrontendIds.remove(new Integer(infos[i].getId()));
|
||||||
|
} else {
|
||||||
|
// Add a new fe resource
|
||||||
|
FrontendResource newFe = new FrontendResource.Builder(infos[i].getId())
|
||||||
|
.type(infos[i].getFrontendType())
|
||||||
|
.exclusiveGroupId(infos[i].getExclusiveGroupId())
|
||||||
|
.build();
|
||||||
|
// Update the exclusive group member list in all the existing Frontend resource
|
||||||
|
for (Integer feId : mAvailableFrontendIds) {
|
||||||
|
FrontendResource fe = getFrontendResource(feId.intValue());
|
||||||
|
if (fe.getExclusiveGroupId() == newFe.getExclusiveGroupId()) {
|
||||||
|
newFe.addExclusiveGroupMemberFeId(fe.getId());
|
||||||
|
newFe.addExclusiveGroupMemberFeId(fe.getExclusiveGroupMemberFeIds());
|
||||||
|
for (Integer excGroupmemberFeId : fe.getExclusiveGroupMemberFeIds()) {
|
||||||
|
getFrontendResource(excGroupmemberFeId.intValue())
|
||||||
|
.addExclusiveGroupMemberFeId(newFe.getId());
|
||||||
|
}
|
||||||
|
fe.addExclusiveGroupMemberFeId(newFe.getId());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Update resource list and available id list
|
||||||
|
mFrontendResources.append(newFe.getId(), newFe);
|
||||||
|
mAvailableFrontendIds.add(newFe.getId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO check if the removing resource is in use or not. Handle the conflict.
|
||||||
|
for (Integer removingId : updatingFrontendIds) {
|
||||||
|
// update the exclusive group id memver list
|
||||||
|
FrontendResource fe = getFrontendResource(removingId.intValue());
|
||||||
|
fe.removeExclusiveGroupMemberFeId(new Integer(fe.getId()));
|
||||||
|
for (Integer excGroupmemberFeId : fe.getExclusiveGroupMemberFeIds()) {
|
||||||
|
getFrontendResource(excGroupmemberFeId.intValue())
|
||||||
|
.removeExclusiveGroupMemberFeId(new Integer(fe.getId()));
|
||||||
|
}
|
||||||
|
mFrontendResources.remove(removingId.intValue());
|
||||||
|
mAvailableFrontendIds.remove(removingId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
protected boolean requestFrontendInternal(TunerFrontendRequest request, int[] frontendId)
|
||||||
|
throws RemoteException {
|
||||||
|
if (DEBUG) {
|
||||||
|
Slog.d(TAG, "requestFrontend(request=" + request + ")");
|
||||||
|
}
|
||||||
|
|
||||||
|
frontendId[0] = TunerResourceManager.INVALID_FRONTEND_ID;
|
||||||
|
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;
|
||||||
|
// Priority max value is 1000
|
||||||
|
int currentLowestPriority = MAX_CLIENT_PRIORITY + 1;
|
||||||
|
for (int id : mAvailableFrontendIds) {
|
||||||
|
FrontendResource fr = getFrontendResource(id);
|
||||||
|
if (fr.getType() == request.getFrontendType()) {
|
||||||
|
if (!fr.isInUse()) {
|
||||||
|
// Grant unused frontend with no exclusive group members first.
|
||||||
|
if (fr.getExclusiveGroupMemberFeIds().size() == 0) {
|
||||||
|
grantingFrontendId = id;
|
||||||
|
break;
|
||||||
|
} else if (grantingFrontendId < 0) {
|
||||||
|
// Grant the unused frontend with lower id first if all the unused
|
||||||
|
// frontends have exclusive group members.
|
||||||
|
grantingFrontendId = id;
|
||||||
|
}
|
||||||
|
} 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(id);
|
||||||
|
if (currentLowestPriority > priority) {
|
||||||
|
inUseLowestPriorityFrId = id;
|
||||||
|
currentLowestPriority = priority;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Grant frontend when there is unused resource.
|
||||||
|
if (grantingFrontendId > -1) {
|
||||||
|
frontendId[0] = grantingFrontendId;
|
||||||
|
updateFrontendClientMappingOnNewGrant(frontendId[0], request.getClientId());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// When all the resources are occupied, grant the lowest priority resource if the
|
||||||
|
// request client has higher priority.
|
||||||
|
if (inUseLowestPriorityFrId > -1 && (requestClient.getPriority() > currentLowestPriority)) {
|
||||||
|
frontendId[0] = inUseLowestPriorityFrId;
|
||||||
|
reclaimFrontendResource(getFrontendResource(frontendId[0]).getOwnerClientId());
|
||||||
|
updateFrontendClientMappingOnNewGrant(frontendId[0], request.getClientId());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
protected int getClientPriority(int useCase, int pid) {
|
||||||
|
if (DEBUG) {
|
||||||
|
Slog.d(TAG, "getClientPriority useCase=" + useCase
|
||||||
|
+ ", pid=" + pid + ")");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isForeground(pid)) {
|
||||||
|
return mPriorityCongfig.getForegroundPriority(useCase);
|
||||||
|
}
|
||||||
|
return mPriorityCongfig.getBackgroundPriority(useCase);
|
||||||
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
protected boolean isForeground(int pid) {
|
||||||
|
// TODO: how to get fg/bg information from pid
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
protected void reclaimFrontendResource(int reclaimingId) throws RemoteException {
|
||||||
|
if (mListeners.get(reclaimingId) != null) {
|
||||||
|
try {
|
||||||
|
mListeners.get(reclaimingId).onReclaimResources();
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
throw e.rethrowFromSystemServer();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateFrontendClientMappingOnNewGrant(int grantingId, int ownerClientId) {
|
||||||
|
FrontendResource grantingFrontend = getFrontendResource(grantingId);
|
||||||
|
ClientProfile ownerProfile = getClientProfile(ownerClientId);
|
||||||
|
grantingFrontend.setOwner(ownerClientId);
|
||||||
|
ownerProfile.useFrontend(grantingId);
|
||||||
|
for (int exclusiveGroupMember : grantingFrontend.getExclusiveGroupMemberFeIds()) {
|
||||||
|
getFrontendResource(exclusiveGroupMember).setOwner(ownerClientId);
|
||||||
|
ownerProfile.useFrontend(exclusiveGroupMember);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the owner client's priority from the frontend id.
|
||||||
|
*
|
||||||
|
* @param frontendId an in use frontend id.
|
||||||
|
* @return the priority of the owner client of the frontend.
|
||||||
|
*/
|
||||||
|
private int getOwnerClientPriority(int frontendId) {
|
||||||
|
return getClientProfile(getFrontendResource(frontendId).getOwnerClientId()).getPriority();
|
||||||
|
}
|
||||||
|
|
||||||
|
private ClientProfile getClientProfile(int clientId) {
|
||||||
|
return mClientProfiles.get(clientId);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected FrontendResource getFrontendResource(int frontendId) {
|
||||||
|
return mFrontendResources.get(frontendId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
protected SparseArray<ClientProfile> getClientProfiles() {
|
||||||
|
return mClientProfiles;
|
||||||
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
protected SparseArray<FrontendResource> getFrontendResources() {
|
||||||
|
return mFrontendResources;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean checkClientExists(int clientId) {
|
||||||
|
return mRegisteredClientIds.contains(clientId);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void enforceAccessPermission() {
|
||||||
|
getContext().enforceCallingOrSelfPermission(
|
||||||
|
"android.permission.TUNER_RESOURCE_ACCESS", TAG);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,236 @@
|
|||||||
|
/*
|
||||||
|
* 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 android.media.tv.TvInputService;
|
||||||
|
import android.media.tv.TvInputService.PriorityHintUseCaseType;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.util.Slog;
|
||||||
|
import android.util.SparseArray;
|
||||||
|
import android.util.Xml;
|
||||||
|
|
||||||
|
import com.android.internal.annotations.VisibleForTesting;
|
||||||
|
|
||||||
|
import org.xmlpull.v1.XmlPullParser;
|
||||||
|
import org.xmlpull.v1.XmlPullParserException;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class provides the Tuner Resource Manager use case priority hints config info including a
|
||||||
|
* parser that can read the xml config from the vendors.
|
||||||
|
*
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
public class UseCasePriorityHints {
|
||||||
|
private static final String TAG = "UseCasePriorityHints";
|
||||||
|
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
|
||||||
|
|
||||||
|
private static final String PATH_TO_VENDOR_CONFIG_XML =
|
||||||
|
"/vendor/etc/tunerResourceManagerUseCaseConfig.xml";
|
||||||
|
private static final int INVALID_PRIORITY_VALUE = -1;
|
||||||
|
private static final int INVALID_USE_CASE = -1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Array of the configured use case priority hints. Key is the use case id. Value is a size 2
|
||||||
|
* int array. The first element carries the priority of the use case on foreground. The second
|
||||||
|
* shows the background priority.
|
||||||
|
*/
|
||||||
|
SparseArray<int[]> mPriorityHints = new SparseArray<>();
|
||||||
|
|
||||||
|
List<Integer> mVendorDefinedUseCase = new ArrayList<>();
|
||||||
|
|
||||||
|
private int mDefaultForeground = 150;
|
||||||
|
private int mDefaultBackground = 50;
|
||||||
|
|
||||||
|
int getForegroundPriority(int useCase) {
|
||||||
|
if (mPriorityHints.get(useCase) != null && mPriorityHints.get(useCase).length == 2) {
|
||||||
|
return mPriorityHints.get(useCase)[0];
|
||||||
|
}
|
||||||
|
return mDefaultForeground;
|
||||||
|
}
|
||||||
|
|
||||||
|
int getBackgroundPriority(int useCase) {
|
||||||
|
if (mPriorityHints.get(useCase) != null && mPriorityHints.get(useCase).length == 2) {
|
||||||
|
return mPriorityHints.get(useCase)[1];
|
||||||
|
}
|
||||||
|
return mDefaultBackground;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean isDefinedUseCase(int useCase) {
|
||||||
|
return (mVendorDefinedUseCase.contains(useCase) || isPredefinedUseCase(useCase));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* To parse the vendor use case config.
|
||||||
|
*/
|
||||||
|
public void parse() {
|
||||||
|
// Override the default priority with vendor setting if available.
|
||||||
|
File file = new File(PATH_TO_VENDOR_CONFIG_XML);
|
||||||
|
if (file.exists()) {
|
||||||
|
try {
|
||||||
|
InputStream in = new FileInputStream(file);
|
||||||
|
parseInternal(in);
|
||||||
|
return;
|
||||||
|
} catch (IOException e) {
|
||||||
|
Slog.e(TAG, "Error reading vendor file: " + file, e);
|
||||||
|
} catch (XmlPullParserException e) {
|
||||||
|
Slog.e(TAG, "Unable to parse vendor file: " + file, e);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (DEBUG) {
|
||||||
|
Slog.i(TAG, "no vendor priority configuration available. Using default priority");
|
||||||
|
}
|
||||||
|
addNewUseCasePriority(TvInputService.PRIORITY_HINT_USE_CASE_TYPE_BACKGROUND, 180, 100);
|
||||||
|
addNewUseCasePriority(TvInputService.PRIORITY_HINT_USE_CASE_TYPE_SCAN, 450, 200);
|
||||||
|
addNewUseCasePriority(TvInputService.PRIORITY_HINT_USE_CASE_TYPE_PLAYBACK, 480, 300);
|
||||||
|
addNewUseCasePriority(TvInputService.PRIORITY_HINT_USE_CASE_TYPE_LIVE, 490, 400);
|
||||||
|
addNewUseCasePriority(TvInputService.PRIORITY_HINT_USE_CASE_TYPE_RECORD, 600, 500);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// We don't use namespaces
|
||||||
|
private static final String NS = null;
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
protected void parseInternal(InputStream in)
|
||||||
|
throws IOException, XmlPullParserException {
|
||||||
|
try {
|
||||||
|
XmlPullParser parser = Xml.newPullParser();
|
||||||
|
parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false);
|
||||||
|
parser.setInput(in, null);
|
||||||
|
parser.nextTag();
|
||||||
|
readUseCase(parser);
|
||||||
|
in.close();
|
||||||
|
} catch (IOException | XmlPullParserException e) {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < mPriorityHints.size(); i++) {
|
||||||
|
int useCase = mPriorityHints.keyAt(i);
|
||||||
|
int[] priorities = mPriorityHints.get(useCase);
|
||||||
|
if (DEBUG) {
|
||||||
|
Slog.d(TAG, "{defaultFg=" + mDefaultForeground
|
||||||
|
+ ", defaultBg=" + mDefaultBackground + "}");
|
||||||
|
Slog.d(TAG, "{useCase=" + useCase
|
||||||
|
+ ", fg=" + priorities[0]
|
||||||
|
+ ", bg=" + priorities[1]
|
||||||
|
+ "}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void readUseCase(XmlPullParser parser)
|
||||||
|
throws XmlPullParserException, IOException {
|
||||||
|
parser.require(XmlPullParser.START_TAG, NS, "config");
|
||||||
|
while (parser.next() != XmlPullParser.END_TAG) {
|
||||||
|
if (parser.getEventType() != XmlPullParser.START_TAG) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
String name = parser.getName();
|
||||||
|
int useCase;
|
||||||
|
if (name.equals("useCaseDefault")) {
|
||||||
|
mDefaultForeground = readAttributeToInt("fgPriority", parser);
|
||||||
|
mDefaultBackground = readAttributeToInt("bgPriority", parser);
|
||||||
|
parser.nextTag();
|
||||||
|
parser.require(XmlPullParser.END_TAG, NS, name);
|
||||||
|
} else if (name.equals("useCasePreDefined")) {
|
||||||
|
useCase = formatTypeToNum("type", parser);
|
||||||
|
if (useCase == INVALID_USE_CASE) {
|
||||||
|
Slog.e(TAG, "Wrong predefined use case name given in the vendor config.");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
addNewUseCasePriority(useCase,
|
||||||
|
readAttributeToInt("fgPriority", parser),
|
||||||
|
readAttributeToInt("bgPriority", parser));
|
||||||
|
parser.nextTag();
|
||||||
|
parser.require(XmlPullParser.END_TAG, NS, name);
|
||||||
|
} else if (name.equals("useCaseVendor")) {
|
||||||
|
useCase = readAttributeToInt("id", parser);
|
||||||
|
addNewUseCasePriority(useCase,
|
||||||
|
readAttributeToInt("fgPriority", parser),
|
||||||
|
readAttributeToInt("bgPriority", parser));
|
||||||
|
mVendorDefinedUseCase.add(useCase);
|
||||||
|
parser.nextTag();
|
||||||
|
parser.require(XmlPullParser.END_TAG, NS, name);
|
||||||
|
} else {
|
||||||
|
skip(parser);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void skip(XmlPullParser parser) throws XmlPullParserException, IOException {
|
||||||
|
if (parser.getEventType() != XmlPullParser.START_TAG) {
|
||||||
|
throw new IllegalStateException();
|
||||||
|
}
|
||||||
|
int depth = 1;
|
||||||
|
while (depth != 0) {
|
||||||
|
switch (parser.next()) {
|
||||||
|
case XmlPullParser.END_TAG:
|
||||||
|
depth--;
|
||||||
|
break;
|
||||||
|
case XmlPullParser.START_TAG:
|
||||||
|
depth++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int readAttributeToInt(String attributeName, XmlPullParser parser) {
|
||||||
|
return Integer.valueOf(parser.getAttributeValue(null, attributeName));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addNewUseCasePriority(int useCase, int fgPriority, int bgPriority) {
|
||||||
|
int[] priorities = {fgPriority, bgPriority};
|
||||||
|
mPriorityHints.append(useCase, priorities);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PriorityHintUseCaseType
|
||||||
|
private static int formatTypeToNum(String attributeName, XmlPullParser parser) {
|
||||||
|
String useCaseName = parser.getAttributeValue(null, attributeName);
|
||||||
|
switch (useCaseName) {
|
||||||
|
case "USE_CASE_BACKGROUND":
|
||||||
|
return TvInputService.PRIORITY_HINT_USE_CASE_TYPE_BACKGROUND;
|
||||||
|
case "USE_CASE_SCAN":
|
||||||
|
return TvInputService.PRIORITY_HINT_USE_CASE_TYPE_SCAN;
|
||||||
|
case "USE_CASE_PLAYBACK":
|
||||||
|
return TvInputService.PRIORITY_HINT_USE_CASE_TYPE_PLAYBACK;
|
||||||
|
case "USE_CASE_LIVE":
|
||||||
|
return TvInputService.PRIORITY_HINT_USE_CASE_TYPE_LIVE;
|
||||||
|
case "USE_CASE_RECORD":
|
||||||
|
return TvInputService.PRIORITY_HINT_USE_CASE_TYPE_RECORD;
|
||||||
|
default:
|
||||||
|
return INVALID_USE_CASE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isPredefinedUseCase(int useCase) {
|
||||||
|
switch (useCase) {
|
||||||
|
case TvInputService.PRIORITY_HINT_USE_CASE_TYPE_BACKGROUND:
|
||||||
|
case TvInputService.PRIORITY_HINT_USE_CASE_TYPE_SCAN:
|
||||||
|
case TvInputService.PRIORITY_HINT_USE_CASE_TYPE_PLAYBACK:
|
||||||
|
case TvInputService.PRIORITY_HINT_USE_CASE_TYPE_LIVE:
|
||||||
|
case TvInputService.PRIORITY_HINT_USE_CASE_TYPE_RECORD:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,497 @@
|
|||||||
|
/*
|
||||||
|
* 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 static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
|
import static org.mockito.Mockito.spy;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.ContextWrapper;
|
||||||
|
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.ResourceClientProfile;
|
||||||
|
import android.media.tv.tunerresourcemanager.TunerFrontendInfo;
|
||||||
|
import android.media.tv.tunerresourcemanager.TunerFrontendRequest;
|
||||||
|
import android.media.tv.tunerresourcemanager.TunerResourceManager;
|
||||||
|
import android.os.RemoteException;
|
||||||
|
import android.util.SparseArray;
|
||||||
|
|
||||||
|
import androidx.test.InstrumentationRegistry;
|
||||||
|
import androidx.test.filters.SmallTest;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.junit.runners.JUnit4;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.MockitoAnnotations;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests for {@link TunerResourceManagerService} class.
|
||||||
|
*/
|
||||||
|
@SmallTest
|
||||||
|
@RunWith(JUnit4.class)
|
||||||
|
public class TunerResourceManagerServiceTest {
|
||||||
|
private static final String TAG = "TunerResourceManagerServiceTest";
|
||||||
|
private Context mContextSpy;
|
||||||
|
@Mock private ITvInputManager mITvInputManagerMock;
|
||||||
|
private TunerResourceManagerService mTunerResourceManagerService;
|
||||||
|
private int mReclaimingId;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() throws Exception {
|
||||||
|
MockitoAnnotations.initMocks(this);
|
||||||
|
TvInputManager tvInputManager = new TvInputManager(mITvInputManagerMock, 0);
|
||||||
|
mContextSpy = spy(new ContextWrapper(InstrumentationRegistry.getTargetContext()));
|
||||||
|
when(mContextSpy.getSystemService(Context.TV_INPUT_SERVICE)).thenReturn(tvInputManager);
|
||||||
|
mTunerResourceManagerService = new TunerResourceManagerService(mContextSpy) {
|
||||||
|
@Override
|
||||||
|
protected void reclaimFrontendResource(int reclaimingId) {
|
||||||
|
mReclaimingId = reclaimingId;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
mTunerResourceManagerService.onStart(true /*isForTesting*/);
|
||||||
|
mReclaimingId = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void setFrontendListTest_addFrontendResources_noExclusiveGroupId() {
|
||||||
|
// Init frontend resources.
|
||||||
|
TunerFrontendInfo[] infos = new TunerFrontendInfo[2];
|
||||||
|
infos[0] =
|
||||||
|
new TunerFrontendInfo(0 /*id*/, FrontendSettings.TYPE_DVBT, 0 /*exclusiveGroupId*/);
|
||||||
|
infos[1] =
|
||||||
|
new TunerFrontendInfo(1 /*id*/, FrontendSettings.TYPE_DVBT, 1 /*exclusiveGroupId*/);
|
||||||
|
mTunerResourceManagerService.setFrontendInfoListInternal(infos);
|
||||||
|
|
||||||
|
SparseArray<FrontendResource> resources =
|
||||||
|
mTunerResourceManagerService.getFrontendResources();
|
||||||
|
assertThat(resources.size()).isEqualTo(infos.length);
|
||||||
|
for (int id = 0; id < infos.length; id++) {
|
||||||
|
FrontendResource fe = resources.get(infos[id].getId());
|
||||||
|
assertThat(fe.getId()).isEqualTo(infos[id].getId());
|
||||||
|
assertThat(fe.getType()).isEqualTo(infos[id].getFrontendType());
|
||||||
|
assertThat(fe.getExclusiveGroupId()).isEqualTo(infos[id].getExclusiveGroupId());
|
||||||
|
assertThat(fe.getExclusiveGroupMemberFeIds().size()).isEqualTo(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void setFrontendListTest_addFrontendResources_underTheSameExclusiveGroupId() {
|
||||||
|
// Init frontend resources.
|
||||||
|
TunerFrontendInfo[] infos = new TunerFrontendInfo[4];
|
||||||
|
infos[0] =
|
||||||
|
new TunerFrontendInfo(0 /*id*/, FrontendSettings.TYPE_DVBT, 0 /*exclusiveGroupId*/);
|
||||||
|
infos[1] =
|
||||||
|
new TunerFrontendInfo(1 /*id*/, FrontendSettings.TYPE_DVBT, 1 /*exclusiveGroupId*/);
|
||||||
|
infos[2] =
|
||||||
|
new TunerFrontendInfo(2 /*id*/, FrontendSettings.TYPE_DVBS, 1 /*exclusiveGroupId*/);
|
||||||
|
infos[3] =
|
||||||
|
new TunerFrontendInfo(3 /*id*/, FrontendSettings.TYPE_ATSC, 1 /*exclusiveGroupId*/);
|
||||||
|
mTunerResourceManagerService.setFrontendInfoListInternal(infos);
|
||||||
|
|
||||||
|
SparseArray<FrontendResource> resources =
|
||||||
|
mTunerResourceManagerService.getFrontendResources();
|
||||||
|
assertThat(resources.size()).isEqualTo(infos.length);
|
||||||
|
for (int id = 0; id < infos.length; id++) {
|
||||||
|
FrontendResource fe = resources.get(infos[id].getId());
|
||||||
|
assertThat(fe.getId()).isEqualTo(infos[id].getId());
|
||||||
|
assertThat(fe.getType()).isEqualTo(infos[id].getFrontendType());
|
||||||
|
assertThat(fe.getExclusiveGroupId()).isEqualTo(infos[id].getExclusiveGroupId());
|
||||||
|
}
|
||||||
|
|
||||||
|
assertThat(resources.get(0).getExclusiveGroupMemberFeIds())
|
||||||
|
.isEqualTo(new ArrayList<Integer>());
|
||||||
|
assertThat(resources.get(1).getExclusiveGroupMemberFeIds())
|
||||||
|
.isEqualTo(new ArrayList<Integer>(Arrays.asList(2, 3)));
|
||||||
|
assertThat(resources.get(2).getExclusiveGroupMemberFeIds())
|
||||||
|
.isEqualTo(new ArrayList<Integer>(Arrays.asList(1, 3)));
|
||||||
|
assertThat(resources.get(3).getExclusiveGroupMemberFeIds())
|
||||||
|
.isEqualTo(new ArrayList<Integer>(Arrays.asList(1, 2)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void setFrontendListTest_updateExistingFrontendResources() {
|
||||||
|
// Init frontend resources.
|
||||||
|
TunerFrontendInfo[] infos = new TunerFrontendInfo[2];
|
||||||
|
infos[0] =
|
||||||
|
new TunerFrontendInfo(0 /*id*/, FrontendSettings.TYPE_DVBT, 1 /*exclusiveGroupId*/);
|
||||||
|
infos[1] =
|
||||||
|
new TunerFrontendInfo(1 /*id*/, FrontendSettings.TYPE_DVBS, 1 /*exclusiveGroupId*/);
|
||||||
|
|
||||||
|
mTunerResourceManagerService.setFrontendInfoListInternal(infos);
|
||||||
|
SparseArray<FrontendResource> resources0 =
|
||||||
|
mTunerResourceManagerService.getFrontendResources();
|
||||||
|
|
||||||
|
mTunerResourceManagerService.setFrontendInfoListInternal(infos);
|
||||||
|
SparseArray<FrontendResource> resources1 =
|
||||||
|
mTunerResourceManagerService.getFrontendResources();
|
||||||
|
|
||||||
|
assertThat(resources0).isEqualTo(resources1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void setFrontendListTest_removeFrontendResources_noExclusiveGroupId() {
|
||||||
|
// Init frontend resources.
|
||||||
|
TunerFrontendInfo[] infos0 = new TunerFrontendInfo[3];
|
||||||
|
infos0[0] =
|
||||||
|
new TunerFrontendInfo(0 /*id*/, FrontendSettings.TYPE_DVBT, 0 /*exclusiveGroupId*/);
|
||||||
|
infos0[1] =
|
||||||
|
new TunerFrontendInfo(1 /*id*/, FrontendSettings.TYPE_DVBT, 1 /*exclusiveGroupId*/);
|
||||||
|
infos0[2] =
|
||||||
|
new TunerFrontendInfo(2 /*id*/, FrontendSettings.TYPE_DVBS, 2 /*exclusiveGroupId*/);
|
||||||
|
mTunerResourceManagerService.setFrontendInfoListInternal(infos0);
|
||||||
|
|
||||||
|
TunerFrontendInfo[] infos1 = new TunerFrontendInfo[1];
|
||||||
|
infos1[0] =
|
||||||
|
new TunerFrontendInfo(1 /*id*/, FrontendSettings.TYPE_DVBT, 1 /*exclusiveGroupId*/);
|
||||||
|
mTunerResourceManagerService.setFrontendInfoListInternal(infos1);
|
||||||
|
|
||||||
|
SparseArray<FrontendResource> resources =
|
||||||
|
mTunerResourceManagerService.getFrontendResources();
|
||||||
|
assertThat(resources.size()).isEqualTo(infos1.length);
|
||||||
|
for (int id = 0; id < infos1.length; id++) {
|
||||||
|
FrontendResource fe = resources.get(infos1[id].getId());
|
||||||
|
assertThat(fe.getId()).isEqualTo(infos1[id].getId());
|
||||||
|
assertThat(fe.getType()).isEqualTo(infos1[id].getFrontendType());
|
||||||
|
assertThat(fe.getExclusiveGroupId()).isEqualTo(infos1[id].getExclusiveGroupId());
|
||||||
|
assertThat(fe.getExclusiveGroupMemberFeIds().size()).isEqualTo(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void setFrontendListTest_removeFrontendResources_underTheSameExclusiveGroupId() {
|
||||||
|
// Init frontend resources.
|
||||||
|
TunerFrontendInfo[] infos0 = new TunerFrontendInfo[3];
|
||||||
|
infos0[0] =
|
||||||
|
new TunerFrontendInfo(0 /*id*/, FrontendSettings.TYPE_DVBT, 0 /*exclusiveGroupId*/);
|
||||||
|
infos0[1] =
|
||||||
|
new TunerFrontendInfo(1 /*id*/, FrontendSettings.TYPE_DVBT, 1 /*exclusiveGroupId*/);
|
||||||
|
infos0[2] =
|
||||||
|
new TunerFrontendInfo(2 /*id*/, FrontendSettings.TYPE_DVBS, 1 /*exclusiveGroupId*/);
|
||||||
|
mTunerResourceManagerService.setFrontendInfoListInternal(infos0);
|
||||||
|
|
||||||
|
TunerFrontendInfo[] infos1 = new TunerFrontendInfo[1];
|
||||||
|
infos1[0] =
|
||||||
|
new TunerFrontendInfo(1 /*id*/, FrontendSettings.TYPE_DVBT, 1 /*exclusiveGroupId*/);
|
||||||
|
mTunerResourceManagerService.setFrontendInfoListInternal(infos1);
|
||||||
|
|
||||||
|
SparseArray<FrontendResource> resources =
|
||||||
|
mTunerResourceManagerService.getFrontendResources();
|
||||||
|
assertThat(resources.size()).isEqualTo(infos1.length);
|
||||||
|
for (int id = 0; id < infos1.length; id++) {
|
||||||
|
FrontendResource fe = resources.get(infos1[id].getId());
|
||||||
|
assertThat(fe.getId()).isEqualTo(infos1[id].getId());
|
||||||
|
assertThat(fe.getType()).isEqualTo(infos1[id].getFrontendType());
|
||||||
|
assertThat(fe.getExclusiveGroupId()).isEqualTo(infos1[id].getExclusiveGroupId());
|
||||||
|
assertThat(fe.getExclusiveGroupMemberFeIds().size()).isEqualTo(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void requestFrontendTest_ClientNotRegistered() {
|
||||||
|
TunerFrontendRequest request =
|
||||||
|
new TunerFrontendRequest(0 /*clientId*/, FrontendSettings.TYPE_DVBT);
|
||||||
|
int[] frontendId = new int[1];
|
||||||
|
try {
|
||||||
|
assertThat(mTunerResourceManagerService.requestFrontendInternal(request, frontendId))
|
||||||
|
.isFalse();
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
throw e.rethrowFromSystemServer();
|
||||||
|
}
|
||||||
|
assertThat(frontendId[0]).isEqualTo(TunerResourceManager.INVALID_FRONTEND_ID);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void requestFrontendTest_NoFrontendWithGiveTypeAvailable() {
|
||||||
|
ResourceClientProfile profile = new ResourceClientProfile("0" /*sessionId*/,
|
||||||
|
TvInputService.PRIORITY_HINT_USE_CASE_TYPE_PLAYBACK);
|
||||||
|
int[] clientId = new int[1];
|
||||||
|
mTunerResourceManagerService.registerClientProfileInternal(
|
||||||
|
profile, null /*listener*/, clientId);
|
||||||
|
assertThat(clientId[0]).isNotEqualTo(TunerResourceManagerService.INVALID_CLIENT_ID);
|
||||||
|
|
||||||
|
// Init frontend resources.
|
||||||
|
TunerFrontendInfo[] infos = new TunerFrontendInfo[1];
|
||||||
|
infos[0] =
|
||||||
|
new TunerFrontendInfo(0 /*id*/, FrontendSettings.TYPE_DVBS, 0 /*exclusiveGroupId*/);
|
||||||
|
mTunerResourceManagerService.setFrontendInfoListInternal(infos);
|
||||||
|
|
||||||
|
TunerFrontendRequest request =
|
||||||
|
new TunerFrontendRequest(clientId[0] /*clientId*/, FrontendSettings.TYPE_DVBT);
|
||||||
|
int[] frontendId = new int[1];
|
||||||
|
try {
|
||||||
|
assertThat(mTunerResourceManagerService.requestFrontendInternal(request, frontendId))
|
||||||
|
.isFalse();
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
throw e.rethrowFromSystemServer();
|
||||||
|
}
|
||||||
|
assertThat(frontendId[0]).isEqualTo(TunerResourceManager.INVALID_FRONTEND_ID);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void requestFrontendTest_FrontendWithNoExclusiveGroupAvailable() {
|
||||||
|
ResourceClientProfile profile = new ResourceClientProfile("0" /*sessionId*/,
|
||||||
|
TvInputService.PRIORITY_HINT_USE_CASE_TYPE_PLAYBACK);
|
||||||
|
int[] clientId = new int[1];
|
||||||
|
mTunerResourceManagerService.registerClientProfileInternal(
|
||||||
|
profile, null /*listener*/, clientId);
|
||||||
|
assertThat(clientId[0]).isNotEqualTo(TunerResourceManagerService.INVALID_CLIENT_ID);
|
||||||
|
|
||||||
|
// Init frontend resources.
|
||||||
|
TunerFrontendInfo[] infos = new TunerFrontendInfo[3];
|
||||||
|
infos[0] =
|
||||||
|
new TunerFrontendInfo(0 /*id*/, FrontendSettings.TYPE_DVBT, 0 /*exclusiveGroupId*/);
|
||||||
|
infos[1] =
|
||||||
|
new TunerFrontendInfo(1 /*id*/, FrontendSettings.TYPE_DVBT, 1 /*exclusiveGroupId*/);
|
||||||
|
infos[2] =
|
||||||
|
new TunerFrontendInfo(2 /*id*/, FrontendSettings.TYPE_DVBS, 1 /*exclusiveGroupId*/);
|
||||||
|
mTunerResourceManagerService.setFrontendInfoListInternal(infos);
|
||||||
|
|
||||||
|
TunerFrontendRequest request =
|
||||||
|
new TunerFrontendRequest(clientId[0] /*clientId*/, FrontendSettings.TYPE_DVBT);
|
||||||
|
int[] frontendId = new int[1];
|
||||||
|
try {
|
||||||
|
assertThat(mTunerResourceManagerService.requestFrontendInternal(request, frontendId))
|
||||||
|
.isTrue();
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
throw e.rethrowFromSystemServer();
|
||||||
|
}
|
||||||
|
assertThat(frontendId[0]).isEqualTo(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void requestFrontendTest_FrontendWithExclusiveGroupAvailable() {
|
||||||
|
ResourceClientProfile profile0 = new ResourceClientProfile("0" /*sessionId*/,
|
||||||
|
TvInputService.PRIORITY_HINT_USE_CASE_TYPE_PLAYBACK);
|
||||||
|
ResourceClientProfile profile1 = new ResourceClientProfile("1" /*sessionId*/,
|
||||||
|
TvInputService.PRIORITY_HINT_USE_CASE_TYPE_PLAYBACK);
|
||||||
|
int[] clientId0 = new int[1];
|
||||||
|
int[] clientId1 = new int[1];
|
||||||
|
mTunerResourceManagerService.registerClientProfileInternal(
|
||||||
|
profile0, null /*listener*/, clientId0);
|
||||||
|
mTunerResourceManagerService.registerClientProfileInternal(
|
||||||
|
profile1, null /*listener*/, clientId1);
|
||||||
|
assertThat(clientId0[0]).isNotEqualTo(TunerResourceManagerService.INVALID_CLIENT_ID);
|
||||||
|
assertThat(clientId1[0]).isNotEqualTo(TunerResourceManagerService.INVALID_CLIENT_ID);
|
||||||
|
|
||||||
|
// Init frontend resources.
|
||||||
|
TunerFrontendInfo[] infos = new TunerFrontendInfo[3];
|
||||||
|
infos[0] =
|
||||||
|
new TunerFrontendInfo(0 /*id*/, FrontendSettings.TYPE_DVBT, 0 /*exclusiveGroupId*/);
|
||||||
|
infos[1] =
|
||||||
|
new TunerFrontendInfo(1 /*id*/, FrontendSettings.TYPE_DVBT, 1 /*exclusiveGroupId*/);
|
||||||
|
infos[2] =
|
||||||
|
new TunerFrontendInfo(2 /*id*/, FrontendSettings.TYPE_DVBS, 1 /*exclusiveGroupId*/);
|
||||||
|
mTunerResourceManagerService.setFrontendInfoListInternal(infos);
|
||||||
|
|
||||||
|
int[] frontendId = new int[1];
|
||||||
|
TunerFrontendRequest request =
|
||||||
|
new TunerFrontendRequest(clientId1[0] /*clientId*/, FrontendSettings.TYPE_DVBT);
|
||||||
|
try {
|
||||||
|
assertThat(mTunerResourceManagerService.requestFrontendInternal(request, frontendId))
|
||||||
|
.isTrue();
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
throw e.rethrowFromSystemServer();
|
||||||
|
}
|
||||||
|
assertThat(frontendId[0]).isEqualTo(infos[0].getId());
|
||||||
|
|
||||||
|
request =
|
||||||
|
new TunerFrontendRequest(clientId0[0] /*clientId*/, FrontendSettings.TYPE_DVBT);
|
||||||
|
try {
|
||||||
|
assertThat(mTunerResourceManagerService.requestFrontendInternal(request, frontendId))
|
||||||
|
.isTrue();
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
throw e.rethrowFromSystemServer();
|
||||||
|
}
|
||||||
|
assertThat(frontendId[0]).isEqualTo(infos[1].getId());
|
||||||
|
assertThat(mTunerResourceManagerService.getFrontendResources().get(infos[1].getId())
|
||||||
|
.isInUse()).isTrue();
|
||||||
|
assertThat(mTunerResourceManagerService.getFrontendResources().get(infos[2].getId())
|
||||||
|
.isInUse()).isTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void requestFrontendTest_NoFrontendAvailable_RequestWithLowerPriority() {
|
||||||
|
// 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, 50};
|
||||||
|
int[] clientId0 = new int[1];
|
||||||
|
int[] clientId1 = new int[1];
|
||||||
|
mTunerResourceManagerService.registerClientProfileInternal(
|
||||||
|
profiles[0], null /*listener*/, clientId0);
|
||||||
|
assertThat(clientId0[0]).isNotEqualTo(TunerResourceManagerService.INVALID_CLIENT_ID);
|
||||||
|
mTunerResourceManagerService.getClientProfiles().get(clientId0[0])
|
||||||
|
.setPriority(clientPriorities[0]);
|
||||||
|
mTunerResourceManagerService.registerClientProfileInternal(
|
||||||
|
profiles[1], null /*listener*/, clientId1);
|
||||||
|
assertThat(clientId1[0]).isNotEqualTo(TunerResourceManagerService.INVALID_CLIENT_ID);
|
||||||
|
mTunerResourceManagerService.getClientProfiles().get(clientId1[0])
|
||||||
|
.setPriority(clientPriorities[1]);
|
||||||
|
|
||||||
|
// Init frontend resources.
|
||||||
|
TunerFrontendInfo[] infos = new TunerFrontendInfo[2];
|
||||||
|
infos[0] =
|
||||||
|
new TunerFrontendInfo(0 /*id*/, FrontendSettings.TYPE_DVBT, 1 /*exclusiveGroupId*/);
|
||||||
|
infos[1] =
|
||||||
|
new TunerFrontendInfo(1 /*id*/, FrontendSettings.TYPE_DVBS, 1 /*exclusiveGroupId*/);
|
||||||
|
mTunerResourceManagerService.setFrontendInfoListInternal(infos);
|
||||||
|
|
||||||
|
TunerFrontendRequest request =
|
||||||
|
new TunerFrontendRequest(clientId0[0] /*clientId*/, FrontendSettings.TYPE_DVBT);
|
||||||
|
int[] frontendId = new int[1];
|
||||||
|
try {
|
||||||
|
assertThat(mTunerResourceManagerService.requestFrontendInternal(request, frontendId))
|
||||||
|
.isTrue();
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
throw e.rethrowFromSystemServer();
|
||||||
|
}
|
||||||
|
|
||||||
|
request =
|
||||||
|
new TunerFrontendRequest(clientId1[0] /*clientId*/, FrontendSettings.TYPE_DVBT);
|
||||||
|
try {
|
||||||
|
assertThat(mTunerResourceManagerService.requestFrontendInternal(request, frontendId))
|
||||||
|
.isFalse();
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
throw e.rethrowFromSystemServer();
|
||||||
|
}
|
||||||
|
assertThat(mReclaimingId).isEqualTo(-1);
|
||||||
|
|
||||||
|
request =
|
||||||
|
new TunerFrontendRequest(clientId1[0] /*clientId*/, FrontendSettings.TYPE_DVBS);
|
||||||
|
try {
|
||||||
|
assertThat(mTunerResourceManagerService.requestFrontendInternal(request, frontendId))
|
||||||
|
.isFalse();
|
||||||
|
assertThat(mReclaimingId).isEqualTo(-1);
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
throw e.rethrowFromSystemServer();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void requestFrontendTest_NoFrontendAvailable_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];
|
||||||
|
mTunerResourceManagerService.registerClientProfileInternal(
|
||||||
|
profiles[0], null /*listener*/, clientId0);
|
||||||
|
assertThat(clientId0[0]).isNotEqualTo(TunerResourceManagerService.INVALID_CLIENT_ID);
|
||||||
|
mTunerResourceManagerService.getClientProfiles().get(clientId0[0])
|
||||||
|
.setPriority(clientPriorities[0]);
|
||||||
|
mTunerResourceManagerService.registerClientProfileInternal(
|
||||||
|
profiles[1], null /*listener*/, clientId1);
|
||||||
|
assertThat(clientId1[0]).isNotEqualTo(TunerResourceManagerService.INVALID_CLIENT_ID);
|
||||||
|
mTunerResourceManagerService.getClientProfiles().get(clientId1[0])
|
||||||
|
.setPriority(clientPriorities[1]);
|
||||||
|
|
||||||
|
// Init frontend resources.
|
||||||
|
TunerFrontendInfo[] infos = new TunerFrontendInfo[2];
|
||||||
|
infos[0] =
|
||||||
|
new TunerFrontendInfo(0 /*id*/, FrontendSettings.TYPE_DVBT, 1 /*exclusiveGroupId*/);
|
||||||
|
infos[1] =
|
||||||
|
new TunerFrontendInfo(1 /*id*/, FrontendSettings.TYPE_DVBS, 1 /*exclusiveGroupId*/);
|
||||||
|
mTunerResourceManagerService.setFrontendInfoListInternal(infos);
|
||||||
|
|
||||||
|
TunerFrontendRequest request =
|
||||||
|
new TunerFrontendRequest(clientId0[0] /*clientId*/, FrontendSettings.TYPE_DVBT);
|
||||||
|
int[] frontendId = new int[1];
|
||||||
|
try {
|
||||||
|
assertThat(mTunerResourceManagerService.requestFrontendInternal(request, frontendId))
|
||||||
|
.isTrue();
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
throw e.rethrowFromSystemServer();
|
||||||
|
}
|
||||||
|
assertThat(frontendId[0]).isEqualTo(infos[0].getId());
|
||||||
|
|
||||||
|
request =
|
||||||
|
new TunerFrontendRequest(clientId1[0] /*clientId*/, FrontendSettings.TYPE_DVBS);
|
||||||
|
try {
|
||||||
|
assertThat(mTunerResourceManagerService.requestFrontendInternal(request, frontendId))
|
||||||
|
.isTrue();
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
throw e.rethrowFromSystemServer();
|
||||||
|
}
|
||||||
|
assertThat(frontendId[0]).isEqualTo(infos[1].getId());
|
||||||
|
assertThat(mTunerResourceManagerService.getFrontendResources().get(infos[0].getId())
|
||||||
|
.isInUse()).isTrue();
|
||||||
|
assertThat(mTunerResourceManagerService.getFrontendResources().get(infos[1].getId())
|
||||||
|
.isInUse()).isTrue();
|
||||||
|
assertThat(mTunerResourceManagerService.getFrontendResources()
|
||||||
|
.get(infos[0].getId()).getOwnerClientId()).isEqualTo(clientId1[0]);
|
||||||
|
assertThat(mTunerResourceManagerService.getFrontendResources()
|
||||||
|
.get(infos[1].getId()).getOwnerClientId()).isEqualTo(clientId1[0]);
|
||||||
|
assertThat(mReclaimingId).isEqualTo(clientId0[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void unregisterClientTest_usingFrontend() {
|
||||||
|
// Register client
|
||||||
|
ResourceClientProfile profile = new ResourceClientProfile("0" /*sessionId*/,
|
||||||
|
TvInputService.PRIORITY_HINT_USE_CASE_TYPE_PLAYBACK);
|
||||||
|
int[] clientId = new int[1];
|
||||||
|
mTunerResourceManagerService.registerClientProfileInternal(
|
||||||
|
profile, null /*listener*/, clientId);
|
||||||
|
assertThat(clientId[0]).isNotEqualTo(TunerResourceManagerService.INVALID_CLIENT_ID);
|
||||||
|
|
||||||
|
// Init frontend resources.
|
||||||
|
TunerFrontendInfo[] infos = new TunerFrontendInfo[2];
|
||||||
|
infos[0] =
|
||||||
|
new TunerFrontendInfo(0 /*id*/, FrontendSettings.TYPE_DVBT, 1 /*exclusiveGroupId*/);
|
||||||
|
infos[1] =
|
||||||
|
new TunerFrontendInfo(1 /*id*/, FrontendSettings.TYPE_DVBS, 1 /*exclusiveGroupId*/);
|
||||||
|
mTunerResourceManagerService.setFrontendInfoListInternal(infos);
|
||||||
|
|
||||||
|
TunerFrontendRequest request =
|
||||||
|
new TunerFrontendRequest(clientId[0] /*clientId*/, FrontendSettings.TYPE_DVBT);
|
||||||
|
int[] frontendId = new int[1];
|
||||||
|
try {
|
||||||
|
assertThat(mTunerResourceManagerService.requestFrontendInternal(request, frontendId))
|
||||||
|
.isTrue();
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
throw e.rethrowFromSystemServer();
|
||||||
|
}
|
||||||
|
assertThat(frontendId[0]).isEqualTo(infos[0].getId());
|
||||||
|
assertThat(mTunerResourceManagerService.getFrontendResources().get(infos[0].getId())
|
||||||
|
.isInUse()).isTrue();
|
||||||
|
assertThat(mTunerResourceManagerService.getFrontendResources().get(infos[1].getId())
|
||||||
|
.isInUse()).isTrue();
|
||||||
|
|
||||||
|
// Unregister client when using frontend
|
||||||
|
mTunerResourceManagerService.unregisterClientProfileInternal(clientId[0]);
|
||||||
|
assertThat(mTunerResourceManagerService.getFrontendResources().get(infos[0].getId())
|
||||||
|
.isInUse()).isFalse();
|
||||||
|
assertThat(mTunerResourceManagerService.getFrontendResources().get(infos[1].getId())
|
||||||
|
.isInUse()).isFalse();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,111 @@
|
|||||||
|
/*
|
||||||
|
* 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 static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
|
import android.media.tv.TvInputService;
|
||||||
|
import android.util.Slog;
|
||||||
|
|
||||||
|
import androidx.test.filters.SmallTest;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.junit.runners.JUnit4;
|
||||||
|
import org.xmlpull.v1.XmlPullParserException;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests for {@link UseCasePriorityHints} class.
|
||||||
|
*/
|
||||||
|
@SmallTest
|
||||||
|
@RunWith(JUnit4.class)
|
||||||
|
public class UseCasePriorityHintsTest {
|
||||||
|
private static final String TAG = "UseCasePriorityHintsTest";
|
||||||
|
private UseCasePriorityHints mPriorityHints;
|
||||||
|
|
||||||
|
private final String mExampleXML =
|
||||||
|
"<!-- A sample Use Case Priority Hints xml -->"
|
||||||
|
+ "<config version=\"1.0\" xmlns:xi=\"http://www.w3.org/2001/XInclude\">"
|
||||||
|
+ "<useCaseDefault fgPriority=\"150\" bgPriority=\"50\"/>"
|
||||||
|
+ "<useCasePreDefined type=\"USE_CASE_RECORD\" fgPriority=\"600\" bgPriority=\"500\"/>"
|
||||||
|
+ "<useCasePreDefined type=\"USE_CASE_LIVE\" fgPriority=\"490\" bgPriority=\"400\"/>"
|
||||||
|
+ "<useCasePreDefined type=\"USE_CASE_PLAYBACK\" fgPriority=\"480\""
|
||||||
|
+ " bgPriority=\"300\"/>"
|
||||||
|
+ "<useCasePreDefined type=\"USE_CASE_BACKGROUND\" fgPriority=\"180\""
|
||||||
|
+ " bgPriority=\"100\"/>"
|
||||||
|
+ "<useCaseVendor type=\"VENDOR_USE_CASE_1\" id=\"1001\" fgPriority=\"300\""
|
||||||
|
+ " bgPriority=\"80\"/>"
|
||||||
|
+ "</config>";
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() throws Exception {
|
||||||
|
mPriorityHints = new UseCasePriorityHints();
|
||||||
|
try {
|
||||||
|
mPriorityHints.parseInternal(
|
||||||
|
new ByteArrayInputStream(mExampleXML.getBytes(StandardCharsets.UTF_8)));
|
||||||
|
} catch (IOException | XmlPullParserException e) {
|
||||||
|
Slog.e(TAG, "Error parse xml.", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void parseTest_parseSampleXml() {
|
||||||
|
// Pre-defined foreground
|
||||||
|
assertThat(mPriorityHints.getForegroundPriority(
|
||||||
|
TvInputService.PRIORITY_HINT_USE_CASE_TYPE_BACKGROUND)).isEqualTo(180);
|
||||||
|
assertThat(mPriorityHints.getForegroundPriority(
|
||||||
|
TvInputService.PRIORITY_HINT_USE_CASE_TYPE_SCAN)).isEqualTo(150);
|
||||||
|
assertThat(mPriorityHints.getForegroundPriority(
|
||||||
|
TvInputService.PRIORITY_HINT_USE_CASE_TYPE_PLAYBACK)).isEqualTo(480);
|
||||||
|
assertThat(mPriorityHints.getForegroundPriority(
|
||||||
|
TvInputService.PRIORITY_HINT_USE_CASE_TYPE_LIVE)).isEqualTo(490);
|
||||||
|
assertThat(mPriorityHints.getForegroundPriority(
|
||||||
|
TvInputService.PRIORITY_HINT_USE_CASE_TYPE_RECORD)).isEqualTo(600);
|
||||||
|
|
||||||
|
// Pre-defined background
|
||||||
|
assertThat(mPriorityHints.getBackgroundPriority(
|
||||||
|
TvInputService.PRIORITY_HINT_USE_CASE_TYPE_BACKGROUND)).isEqualTo(100);
|
||||||
|
assertThat(mPriorityHints.getBackgroundPriority(
|
||||||
|
TvInputService.PRIORITY_HINT_USE_CASE_TYPE_SCAN)).isEqualTo(50);
|
||||||
|
assertThat(mPriorityHints.getBackgroundPriority(
|
||||||
|
TvInputService.PRIORITY_HINT_USE_CASE_TYPE_PLAYBACK)).isEqualTo(300);
|
||||||
|
assertThat(mPriorityHints.getBackgroundPriority(
|
||||||
|
TvInputService.PRIORITY_HINT_USE_CASE_TYPE_LIVE)).isEqualTo(400);
|
||||||
|
assertThat(mPriorityHints.getBackgroundPriority(
|
||||||
|
TvInputService.PRIORITY_HINT_USE_CASE_TYPE_RECORD)).isEqualTo(500);
|
||||||
|
|
||||||
|
// Vendor use case
|
||||||
|
assertThat(mPriorityHints.getForegroundPriority(1001)).isEqualTo(300);
|
||||||
|
assertThat(mPriorityHints.getBackgroundPriority(1001)).isEqualTo(80);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void isDefinedUseCaseTest_invalidUseCase() {
|
||||||
|
assertThat(mPriorityHints.isDefinedUseCase(1992)).isFalse();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void isDefinedUseCaseTest_validUseCase() {
|
||||||
|
assertThat(mPriorityHints.isDefinedUseCase(1001)).isTrue();
|
||||||
|
assertThat(mPriorityHints.isDefinedUseCase(
|
||||||
|
TvInputService.PRIORITY_HINT_USE_CASE_TYPE_RECORD)).isTrue();
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user