blob: c9713220d6e884ea1dc5f46219494ab2c89cf9c0 [file] [log] [blame]
/*
* Copyright (C) 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.integrity.parser;
import static com.android.server.integrity.model.IndexingFileConstants.END_INDEXING_KEY;
import static com.android.server.integrity.model.IndexingFileConstants.START_INDEXING_KEY;
import static com.android.server.integrity.parser.BinaryFileOperations.getIntValue;
import static com.android.server.integrity.parser.BinaryFileOperations.getStringValue;
import android.content.integrity.AppInstallMetadata;
import com.android.server.integrity.model.BitInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.TreeSet;
import java.util.stream.Collectors;
/** Helper class to identify the necessary indexes that needs to be read. */
public class RuleIndexingController {
private static LinkedHashMap<String, Integer> sPackageNameBasedIndexes;
private static LinkedHashMap<String, Integer> sAppCertificateBasedIndexes;
private static LinkedHashMap<String, Integer> sUnindexedRuleIndexes;
/**
* Provide the indexing file to read and the object will be constructed by reading and
* identifying the indexes.
*/
public RuleIndexingController(InputStream inputStream) throws IOException {
BitInputStream bitInputStream = new BitInputStream(inputStream);
sPackageNameBasedIndexes = getNextIndexGroup(bitInputStream);
sAppCertificateBasedIndexes = getNextIndexGroup(bitInputStream);
sUnindexedRuleIndexes = getNextIndexGroup(bitInputStream);
}
/**
* Returns a list of integers with the starting and ending bytes of the rules that needs to be
* read and evaluated.
*/
public List<RuleIndexRange> identifyRulesToEvaluate(AppInstallMetadata appInstallMetadata) {
ArrayList<RuleIndexRange> indexRanges = new ArrayList();
// Add the range for package name indexes rules.
indexRanges.add(
searchIndexingKeysRangeContainingKey(
sPackageNameBasedIndexes, appInstallMetadata.getPackageName()));
// Add the range for app certificate indexes rules.
indexRanges.add(
searchIndexingKeysRangeContainingKey(
sAppCertificateBasedIndexes, appInstallMetadata.getAppCertificate()));
// Add the range for unindexed rules.
indexRanges.add(
new RuleIndexRange(
sUnindexedRuleIndexes.get(START_INDEXING_KEY),
sUnindexedRuleIndexes.get(END_INDEXING_KEY)));
return indexRanges;
}
private LinkedHashMap<String, Integer> getNextIndexGroup(BitInputStream bitInputStream)
throws IOException {
LinkedHashMap<String, Integer> keyToIndexMap = new LinkedHashMap<>();
while (bitInputStream.hasNext()) {
String key = getStringValue(bitInputStream);
int value = getIntValue(bitInputStream);
keyToIndexMap.put(key, value);
if (key.matches(END_INDEXING_KEY)) {
break;
}
}
return keyToIndexMap;
}
private RuleIndexRange searchIndexingKeysRangeContainingKey(
LinkedHashMap<String, Integer> indexMap, String searchedKey) {
TreeSet<String> keyTreeSet =
indexMap.keySet().stream()
.filter(key -> !key.matches(START_INDEXING_KEY) && !key.matches(
END_INDEXING_KEY))
.collect(Collectors.toCollection(TreeSet::new));
String minIndex = keyTreeSet.floor(searchedKey);
String maxIndex = keyTreeSet.ceiling(searchedKey);
return new RuleIndexRange(
indexMap.get(minIndex == null ? START_INDEXING_KEY : minIndex),
indexMap.get(maxIndex == null ? END_INDEXING_KEY : maxIndex));
}
}