Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7872b0c0 authored by Treehugger Robot's avatar Treehugger Robot Committed by Gerrit Code Review
Browse files

Merge "Remove RuleIndexingController as it is no longer referenced after the...

Merge "Remove RuleIndexingController as it is no longer referenced after the deletion of IntegrityFileManager." into main
parents d4ac5371 73e56628
Loading
Loading
Loading
Loading
+1 −2
Original line number Diff line number Diff line
@@ -19,8 +19,7 @@ package com.android.server.integrity.parser;
import android.annotation.Nullable;

/**
 * A wrapper class to represent an indexing range that is identified by the {@link
 * RuleIndexingController}.
 * A wrapper class to represent an indexing range.
 */
public class RuleIndexRange {
    private int mStartIndex;
+0 −128
Original line number Diff line number Diff line
/*
 * 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.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
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) {
        List<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 of all certificates.
        for (String appCertificate : appInstallMetadata.getAppCertificates()) {
            indexRanges.add(
                    searchIndexingKeysRangeContainingKey(
                            sAppCertificateBasedIndexes, appCertificate));
        }

        // 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;
            }
        }
        if (keyToIndexMap.size() < 2) {
            throw new IllegalStateException("Indexing file is corrupt.");
        }
        return keyToIndexMap;
    }

    private static RuleIndexRange searchIndexingKeysRangeContainingKey(
            LinkedHashMap<String, Integer> indexMap, String searchedKey) {
        List<String> keys = indexMap.keySet().stream().collect(Collectors.toList());
        List<String> identifiedKeyRange =
                searchKeysRangeContainingKey(keys, searchedKey, 0, keys.size() - 1);
        return new RuleIndexRange(
                indexMap.get(identifiedKeyRange.get(0)), indexMap.get(identifiedKeyRange.get(1)));
    }

    private static List<String> searchKeysRangeContainingKey(
            List<String> sortedKeyList, String key, int startIndex, int endIndex) {
        if (endIndex <= startIndex) {
            throw new IllegalStateException("Indexing file is corrupt.");
        }
        if (endIndex - startIndex == 1) {
            return Arrays.asList(sortedKeyList.get(startIndex), sortedKeyList.get(endIndex));
        }

        int midKeyIndex = startIndex + ((endIndex - startIndex) / 2);
        String midKey = sortedKeyList.get(midKeyIndex);

        if (key.compareTo(midKey) >= 0) {
            return searchKeysRangeContainingKey(sortedKeyList, key, midKeyIndex, endIndex);
        } else {
            return searchKeysRangeContainingKey(sortedKeyList, key, startIndex, midKeyIndex);
        }
    }
}
+0 −216
Original line number Diff line number Diff line
/*
 * 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.ComponentBitSize.VALUE_SIZE_BITS;
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.utils.TestUtils.getBits;
import static com.android.server.integrity.utils.TestUtils.getBytes;
import static com.android.server.integrity.utils.TestUtils.getValueBits;

import static com.google.common.truth.Truth.assertThat;

import static org.testng.Assert.assertThrows;

import android.content.integrity.AppInstallMetadata;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

@RunWith(JUnit4.class)
public class RuleIndexingControllerTest {

    @Test
    public void verifyIndexRangeSearchIsCorrect() throws IOException {
        InputStream inputStream = obtainDefaultIndexingMapForTest();

        RuleIndexingController indexingController = new RuleIndexingController(inputStream);

        AppInstallMetadata appInstallMetadata =
                new AppInstallMetadata.Builder()
                        .setPackageName("ddd")
                        .setAppCertificates(Collections.singletonList("777"))
                        .setAppCertificateLineage(Collections.singletonList("777"))
                        .build();

        List<RuleIndexRange> resultingIndexes =
                indexingController.identifyRulesToEvaluate(appInstallMetadata);

        assertThat(resultingIndexes)
                .containsExactly(
                        new RuleIndexRange(200, 300),
                        new RuleIndexRange(700, 800),
                        new RuleIndexRange(900, 945));
    }

    @Test
    public void verifyIndexRangeSearchIsCorrect_multipleAppCertificates() throws IOException {
        InputStream inputStream = obtainDefaultIndexingMapForTest();

        RuleIndexingController indexingController = new RuleIndexingController(inputStream);

        AppInstallMetadata appInstallMetadata =
                new AppInstallMetadata.Builder()
                        .setPackageName("ddd")
                        .setAppCertificates(Arrays.asList("777", "999"))
                        .setAppCertificateLineage(Arrays.asList("777", "999"))
                        .build();

        List<RuleIndexRange> resultingIndexes =
                indexingController.identifyRulesToEvaluate(appInstallMetadata);

        assertThat(resultingIndexes)
                .containsExactly(
                        new RuleIndexRange(200, 300),
                        new RuleIndexRange(700, 800),
                        new RuleIndexRange(800, 900),
                        new RuleIndexRange(900, 945));
    }

    @Test
    public void verifyIndexRangeSearchIsCorrect_keysInFirstAndLastBlock() throws IOException {
        InputStream inputStream = obtainDefaultIndexingMapForTest();

        RuleIndexingController indexingController = new RuleIndexingController(inputStream);

        AppInstallMetadata appInstallMetadata =
                new AppInstallMetadata.Builder()
                        .setPackageName("bbb")
                        .setAppCertificates(Collections.singletonList("999"))
                        .setAppCertificateLineage(Collections.singletonList("999"))
                        .build();

        List<RuleIndexRange> resultingIndexes =
                indexingController.identifyRulesToEvaluate(appInstallMetadata);

        assertThat(resultingIndexes)
                .containsExactly(
                        new RuleIndexRange(100, 200),
                        new RuleIndexRange(800, 900),
                        new RuleIndexRange(900, 945));
    }

    @Test
    public void verifyIndexRangeSearchIsCorrect_keysMatchWithValues() throws IOException {
        InputStream inputStream = obtainDefaultIndexingMapForTest();

        RuleIndexingController indexingController = new RuleIndexingController(inputStream);

        AppInstallMetadata appInstallMetadata =
                new AppInstallMetadata.Builder()
                        .setPackageName("ccc")
                        .setAppCertificates(Collections.singletonList("444"))
                        .setAppCertificateLineage(Collections.singletonList("444"))
                        .build();

        List<RuleIndexRange> resultingIndexes =
                indexingController.identifyRulesToEvaluate(appInstallMetadata);

        assertThat(resultingIndexes)
                .containsExactly(
                        new RuleIndexRange(200, 300),
                        new RuleIndexRange(700, 800),
                        new RuleIndexRange(900, 945));
    }

    @Test
    public void verifyIndexRangeSearchIsCorrect_noIndexesAvailable() throws IOException {
        byte[] stringBytes =
                getBytes(
                        getKeyValueString(START_INDEXING_KEY, 100)
                                + getKeyValueString(END_INDEXING_KEY, 500)
                                + getKeyValueString(START_INDEXING_KEY, 500)
                                + getKeyValueString(END_INDEXING_KEY, 900)
                                + getKeyValueString(START_INDEXING_KEY, 900)
                                + getKeyValueString(END_INDEXING_KEY, 945));
        ByteBuffer rule = ByteBuffer.allocate(stringBytes.length);
        rule.put(stringBytes);
        InputStream inputStream = new ByteArrayInputStream(rule.array());

        RuleIndexingController indexingController = new RuleIndexingController(inputStream);

        AppInstallMetadata appInstallMetadata =
                new AppInstallMetadata.Builder()
                        .setPackageName("ccc")
                        .setAppCertificates(Collections.singletonList("444"))
                        .setAppCertificateLineage(Collections.singletonList("444"))
                        .build();

        List<RuleIndexRange> resultingIndexes =
                indexingController.identifyRulesToEvaluate(appInstallMetadata);

        assertThat(resultingIndexes)
                .containsExactly(
                        new RuleIndexRange(100, 500),
                        new RuleIndexRange(500, 900),
                        new RuleIndexRange(900, 945));
    }

    @Test
    public void verifyIndexingFileIsCorrupt() throws IOException {
        byte[] stringBytes =
                getBytes(
                        getKeyValueString(START_INDEXING_KEY, 100)
                                + getKeyValueString("ccc", 200)
                                + getKeyValueString(END_INDEXING_KEY, 300)
                                + getKeyValueString(END_INDEXING_KEY, 900));
        ByteBuffer rule = ByteBuffer.allocate(stringBytes.length);
        rule.put(stringBytes);
        InputStream inputStream = new ByteArrayInputStream(rule.array());

        assertThrows(IllegalStateException.class,
                () -> new RuleIndexingController(inputStream));
    }

    private static InputStream obtainDefaultIndexingMapForTest() {
        byte[] stringBytes =
                getBytes(
                        getKeyValueString(START_INDEXING_KEY, 100)
                                + getKeyValueString("ccc", 200)
                                + getKeyValueString("eee", 300)
                                + getKeyValueString("hhh", 400)
                                + getKeyValueString(END_INDEXING_KEY, 500)
                                + getKeyValueString(START_INDEXING_KEY, 500)
                                + getKeyValueString("111", 600)
                                + getKeyValueString("444", 700)
                                + getKeyValueString("888", 800)
                                + getKeyValueString(END_INDEXING_KEY, 900)
                                + getKeyValueString(START_INDEXING_KEY, 900)
                                + getKeyValueString(END_INDEXING_KEY, 945));
        ByteBuffer rule = ByteBuffer.allocate(stringBytes.length);
        rule.put(stringBytes);
        return new ByteArrayInputStream(rule.array());
    }

    private static String getKeyValueString(String key, int value) {
        String isNotHashed = "0";
        return isNotHashed
                + getBits(key.length(), VALUE_SIZE_BITS)
                + getValueBits(key)
                + getBits(value, /* numOfBits= */ 32);
    }
}