Add a TRM use case priority hints info object
This object includes a parser that reads the vendor config xml
Test: atest UseCasePriorityHintsTest
Bug: 147380513
Change-Id: I4bff0bc196a0c2a78ce4305acec7ce7cc9a4fa70
(cherry picked from commit 2f62bf64ca)
This commit is contained in:
@@ -65,6 +65,7 @@ public class TunerResourceManagerService extends SystemService {
|
||||
private SparseArray<IResourcesReclaimListener> mListeners = new SparseArray<>();
|
||||
|
||||
private TvInputManager mManager;
|
||||
private UseCasePriorityHints mPriorityCongfig = new UseCasePriorityHints();
|
||||
|
||||
// Used to synchronize the access to the service.
|
||||
private final Object mLock = new Object();
|
||||
@@ -84,6 +85,7 @@ public class TunerResourceManagerService extends SystemService {
|
||||
publishBinderService(Context.TV_TUNER_RESOURCE_MGR_SERVICE, new BinderService());
|
||||
}
|
||||
mManager = (TvInputManager) getContext().getSystemService(Context.TV_INPUT_SERVICE);
|
||||
mPriorityCongfig.parse();
|
||||
}
|
||||
|
||||
private final class BinderService extends ITunerResourceManager.Stub {
|
||||
@@ -409,14 +411,21 @@ public class TunerResourceManagerService extends SystemService {
|
||||
|
||||
@VisibleForTesting
|
||||
protected int getClientPriority(int useCase, int callingPid) {
|
||||
// TODO: how to get fg/bg information from pid
|
||||
if (DEBUG) {
|
||||
Slog.d(TAG, "getClientPriority useCase=" + useCase
|
||||
+ ", calling Pid=" + callingPid + ")");
|
||||
}
|
||||
|
||||
// TODO: get priority from the table built from the useCase config xml
|
||||
return 0;
|
||||
if (isForeground(callingPid)) {
|
||||
return mPriorityCongfig.getForegroundPriority(useCase);
|
||||
}
|
||||
return mPriorityCongfig.getBackgroundPriority(useCase);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
protected boolean isForeground(int callingPid) {
|
||||
// TODO: how to get fg/bg information from pid
|
||||
return true;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
|
||||
@@ -0,0 +1,234 @@
|
||||
/*
|
||||
* 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,100 @@
|
||||
/*
|
||||
* 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();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parseTest_parseSampleXml() {
|
||||
try {
|
||||
mPriorityHints.parseInternal(
|
||||
new ByteArrayInputStream(mExampleXML.getBytes(StandardCharsets.UTF_8)));
|
||||
} catch (IOException | XmlPullParserException e) {
|
||||
Slog.e(TAG, "Error parse xml.", e);
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user