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

Commit 2b0b50d2 authored by Alan Stokes's avatar Alan Stokes
Browse files

Add unit tests for DexLogger.

Bug: 63927552
Test: runtest frameworks-services -c com.android.server.pm.dex.DexLoggerTests --install=".*FrameworksServicesTests.apk"
Change-Id: I5f775b5309060c78cb6aaf0c28c4aa777ff11e8e
parent a98bd998
Loading
Loading
Loading
Loading
+13 −6
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@ import android.util.PackageUtils;
import android.util.Slog;

import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.pm.Installer;
import com.android.server.pm.Installer.InstallerException;

@@ -57,7 +58,8 @@ public class DexLogger implements DexManager.Listener {
        return new DexLogger(pms, installer, installLock);
    }

    private DexLogger(IPackageManager pms, Installer installer, Object installLock) {
    @VisibleForTesting
    /*package*/ DexLogger(IPackageManager pms, Installer installer, Object installLock) {
        mPackageManager = pms;
        mInstaller = installer;
        mInstallLock = installLock;
@@ -92,7 +94,7 @@ public class DexLogger implements DexManager.Listener {
            message = message + ' ' + ByteStringUtils.toHexString(hash);
        }

        EventLog.writeEvent(SNET_TAG, DCL_SUBTAG, ownerUid, message);
        writeDclEvent(ownerUid, message);

        if (dexUseInfo.isUsedByOtherApps()) {
            Set<String> otherPackages = dexUseInfo.getLoadingPackages();
@@ -109,8 +111,13 @@ public class DexLogger implements DexManager.Listener {
                }
            }
            for (int otherUid : otherUids) {
                EventLog.writeEvent(SNET_TAG, DCL_SUBTAG, otherUid, message);
                writeDclEvent(otherUid, message);
            }
        }
    }

    @VisibleForTesting
    /*package*/ void writeDclEvent(int uid, String message) {
        EventLog.writeEvent(SNET_TAG, DCL_SUBTAG, uid, message);
    }
}
+166 −0
Original line number Diff line number Diff line
/*
 * Copyright 2017 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.pm.dex;

import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager;
import android.content.pm.PackageInfo;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
import android.os.storage.StorageManager;

import com.android.server.pm.Installer;
import com.android.server.pm.Installer.InstallerException;

import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.ListMultimap;

import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
import org.mockito.quality.Strictness;

import java.util.Arrays;

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

import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.doThrow;

import static com.android.server.pm.dex.PackageDexUsage.PackageUseInfo;
import static com.android.server.pm.dex.PackageDexUsage.DexUseInfo;

@RunWith(AndroidJUnit4.class)
@SmallTest
public class DexLoggerTests {
    private static final String PACKAGE_NAME = "package.name";
    private static final String VOLUME_UUID = "volUuid";
    private static final String DEX_PATH = "/bar/foo.jar";
    private static final int STORAGE_FLAGS = StorageManager.FLAG_STORAGE_DE;
    private static final int OWNER_UID = 43;
    private static final int OWNER_USER_ID = 44;

    // Obtained via: echo -n "foo.jar" | sha256sum
    private static final String DEX_FILENAME_HASH =
            "91D7B844D7CC9673748FF057D8DC83972280FC28537D381AA42015A9CF214B9F";

    private static final byte[] CONTENT_HASH_BYTES = new byte[] {
        1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
        17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32
    };
    private static final String CONTENT_HASH =
            "0102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F20";

    @Rule public MockitoRule mockito = MockitoJUnit.rule().strictness(Strictness.STRICT_STUBS);

    @Mock IPackageManager mPM;
    @Mock Installer mInstaller;
    private final Object mInstallLock = new Object();

    private DexManager.Listener mListener;

    private final ListMultimap<Integer, String> mMessagesForUid = ArrayListMultimap.create();

    @Before
    public void setup() {
        // For test purposes capture log messages as well as sending to the event log.
        mListener = new DexLogger(mPM, mInstaller, mInstallLock) {
                @Override
                void writeDclEvent(int uid, String message) {
                    super.writeDclEvent(uid, message);
                    mMessagesForUid.put(uid, message);
                }
            };
    }

    @Test
    public void testSingleAppWithFileHash() throws Exception {
        doReturn(CONTENT_HASH_BYTES).when(mInstaller).hashSecondaryDexFile(
            DEX_PATH, PACKAGE_NAME, OWNER_UID, VOLUME_UUID, STORAGE_FLAGS);

        runOnReconcile();

        assertThat(mMessagesForUid.keySet()).containsExactly(OWNER_UID);
        String expectedMessage = DEX_FILENAME_HASH + " " + CONTENT_HASH;
        assertThat(mMessagesForUid).containsEntry(OWNER_UID, expectedMessage);
    }

    @Test
    public void testSingleAppNoFileHash() throws Exception {
        doReturn(new byte[] { }).when(mInstaller).hashSecondaryDexFile(
            DEX_PATH, PACKAGE_NAME, OWNER_UID, VOLUME_UUID, STORAGE_FLAGS);

        runOnReconcile();

        assertThat(mMessagesForUid.keySet()).containsExactly(OWNER_UID);
        assertThat(mMessagesForUid).containsEntry(OWNER_UID, DEX_FILENAME_HASH);
    }

    @Test
    public void testSingleAppHashFails() throws Exception {
        doThrow(new InstallerException("Testing failure")).when(mInstaller).hashSecondaryDexFile(
            DEX_PATH, PACKAGE_NAME, OWNER_UID, VOLUME_UUID, STORAGE_FLAGS);

        runOnReconcile();

        assertThat(mMessagesForUid).isEmpty();
    }

    @Test
    public void testOtherApps() throws Exception {
        doReturn(CONTENT_HASH_BYTES).when(mInstaller).hashSecondaryDexFile(
            DEX_PATH, PACKAGE_NAME, OWNER_UID, VOLUME_UUID, STORAGE_FLAGS);

        // Simulate three packages from two different UIDs
        String packageName1 = "other1.package.name";
        String packageName2 = "other2.package.name";
        String packageName3 = "other3.package.name";
        int uid1 = 1001;
        int uid2 = 1002;

        doReturn(uid1).when(mPM).getPackageUid(packageName1, 0, OWNER_USER_ID);
        doReturn(uid2).when(mPM).getPackageUid(packageName2, 0, OWNER_USER_ID);
        doReturn(uid1).when(mPM).getPackageUid(packageName3, 0, OWNER_USER_ID);

        runOnReconcile(packageName1, packageName2, packageName3);

        assertThat(mMessagesForUid.keySet()).containsExactly(OWNER_UID, uid1, uid2);

        String expectedMessage = DEX_FILENAME_HASH + " " + CONTENT_HASH;
        assertThat(mMessagesForUid).containsEntry(OWNER_UID, expectedMessage);
        assertThat(mMessagesForUid).containsEntry(uid1, expectedMessage);
        assertThat(mMessagesForUid).containsEntry(uid2, expectedMessage);
    }

    private void runOnReconcile(String... otherPackageNames) {
        ApplicationInfo appInfo = new ApplicationInfo();
        appInfo.packageName = PACKAGE_NAME;
        appInfo.volumeUuid = VOLUME_UUID;
        appInfo.uid = OWNER_UID;

        boolean isUsedByOtherApps = otherPackageNames.length > 0;
        DexUseInfo dexUseInfo = new DexUseInfo(
            isUsedByOtherApps, OWNER_USER_ID, /* classLoaderContext */ null, /* loaderIsa */ null);
        dexUseInfo.getLoadingPackages().addAll(Arrays.asList(otherPackageNames));

        mListener.onReconcileSecondaryDexFile(appInfo, dexUseInfo, DEX_PATH, STORAGE_FLAGS);
    }
}