| /* |
| * 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)); |
| } |
| } |