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

Commit 40670822 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Automerger Merge Worker
Browse files

Merge "Add SystemPartitionParseTest to postsubmit" into rvc-dev am: 8ced9207

Change-Id: I9cd7efec134b1d6334d76adb0eeca5ae31326e64
parents 50e1f45b 8ced9207
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -118,6 +118,9 @@
        },
        {
          "include-filter": "com.android.server.pm.UserSystemPackageInstallerTest"
        },
        {
          "include-filter": "com.android.server.pm.parsing.SystemPartitionParseTest"
        }
      ]
    }
+19 −46
Original line number Diff line number Diff line
@@ -23,7 +23,6 @@ import android.content.pm.ConfigurationInfo
import android.content.pm.FeatureInfo
import android.content.pm.InstrumentationInfo
import android.content.pm.PackageInfo
import android.content.pm.PackageManager
import android.content.pm.PackageParser
import android.content.pm.PackageUserState
import android.content.pm.PermissionInfo
@@ -38,7 +37,6 @@ import com.android.server.pm.parsing.pkg.AndroidPackage
import com.android.server.pm.pkg.PackageStateUnserialized
import com.android.server.testutils.mockThrowOnUnmocked
import com.android.server.testutils.whenever
import org.junit.After
import org.junit.BeforeClass
import org.mockito.Mockito
import org.mockito.Mockito.anyInt
@@ -49,7 +47,7 @@ open class AndroidPackageParsingTestBase {

    companion object {

        private const val VERIFY_ALL_APKS = true
        private const val VERIFY_ALL_APKS = false

        /** For auditing memory usage differences */
        private const val DUMP_HPROF_TO_EXTERNAL = false
@@ -93,21 +91,25 @@ open class AndroidPackageParsingTestBase {

        lateinit var newPackages: List<AndroidPackage>

        private val thrownInSetUp = mutableListOf<Throwable>()

        @Suppress("ConstantConditionIf")
        @JvmStatic
        @BeforeClass
        fun setUpPackages() {
            this.oldPackages = apks.mapNotNull {
                tryOrNull {
                try {
                    packageParser.parsePackage(it, PackageParser.PARSE_IS_SYSTEM_DIR, false)
                } catch (ignored: Exception) {
                    // Parsing issues will be caught by SystemPartitionParseTest
                    null
                }
            }

            this.newPackages = apks.mapNotNull {
                tryOrNull {
                try {
                    packageParser2.parsePackage(it, PackageParser.PARSE_IS_SYSTEM_DIR, false)
                } catch (ignored: Exception) {
                    // Parsing issues will be caught by SystemPartitionParseTest
                    null
                }
            }

@@ -144,41 +146,6 @@ open class AndroidPackageParsingTestBase {
            this.pkg = aPkg
            whenever(pkgState) { PackageStateUnserialized() }
        }

        private fun <T> tryOrNull(block: () -> T) = try {
            block()
        } catch (e: PackageParser.PackageParserException) {
            if (e.error != PackageManager.INSTALL_PARSE_FAILED_SKIPPED) {
                thrownInSetUp.add(e)
            }
            null
        } catch (t: Throwable) {
            thrownInSetUp.add(t)
            null
        }
    }

    @After
    fun verifySetUpPackages() {
        if (thrownInSetUp.isEmpty()) return
        val exception = AssertionError("setUpPackages failed with ${thrownInSetUp.size} errors:\n" +
                thrownInSetUp.joinToString(separator = "\n") { it.message.orEmpty() })

        /*
            Testing infrastructure doesn't currently support errors thrown in @AfterClass,
            so instead it's thrown here. But to avoid throwing a massive repeated stack for every
            test method, only throw on the first method run in the class, clearing the list so that
            subsequent methods can run without failing. Doing this in @After lets true method
            failures propagate, as those should throw before this does.

            This will cause the failure to be attached to a different method depending on run order,
            which could make comparisons difficult. So if a failure points here, it's worth
            checking failures for all methods in all subclasses.

            TODO: When infrastructure supports @AfterClass errors, move this
        */
        thrownInSetUp.clear()
        throw exception
    }

    // The following methods dump an exact set of fields from the object to compare, because
@@ -285,7 +252,8 @@ open class AndroidPackageParsingTestBase {
            secondaryCpuAbi=${this.secondaryCpuAbi}
            secondaryNativeLibraryDir=${this.secondaryNativeLibraryDir}
            sourceDir=${this.sourceDir}
            splitDependencies=${this.splitDependencies.sequence().map { it.first to it.second?.contentToString() }.joinToString()}
            splitDependencies=${this.splitDependencies.sequence()
            .map { it.first to it.second?.contentToString() }.joinToString()}
            splitNames=${this.splitNames?.contentToString()}
            splitPublicSourceDirs=${this.splitPublicSourceDirs?.contentToString()}
            splitSourceDirs=${this.splitSourceDirs?.contentToString()}
@@ -348,7 +316,9 @@ open class AndroidPackageParsingTestBase {
            initOrder=${this.initOrder}
            isSyncable=${this.isSyncable}
            multiprocess=${this.multiprocess}
            pathPermissions=${this.pathPermissions?.joinToString { "readPermission=${it.readPermission}\nwritePermission=${it.writePermission}" }}
            pathPermissions=${this.pathPermissions?.joinToString {
        "readPermission=${it.readPermission}\nwritePermission=${it.writePermission}"
    }}
            readPermission=${this.readPermission}
            uriPermissionPatterns=${this.uriPermissionPatterns?.contentToString()}
            writePermission=${this.writePermission}
@@ -370,7 +340,9 @@ open class AndroidPackageParsingTestBase {
            compileSdkVersionCodename=${this.compileSdkVersionCodename}
            configPreferences=${this.configPreferences?.joinToString { it.dumpToString() }}
            coreApp=${this.coreApp}
            featureGroups=${this.featureGroups?.joinToString { it.features?.joinToString { featureInfo -> featureInfo.dumpToString() }.orEmpty() }}
            featureGroups=${this.featureGroups?.joinToString {
        it.features?.joinToString { featureInfo -> featureInfo.dumpToString() }.orEmpty()
    }}
            firstInstallTime=${this.firstInstallTime}
            gids=${gids?.contentToString()}
            installLocation=${this.installLocation}
@@ -396,7 +368,8 @@ open class AndroidPackageParsingTestBase {
            sharedUserId=${this.sharedUserId}
            sharedUserLabel=${this.sharedUserLabel}
            signatures=${this.signatures?.joinToString { it.toCharsString() }}
            signingInfo=${this.signingInfo?.signingCertificateHistory?.joinToString { it.toCharsString() }.orEmpty()}
            signingInfo=${this.signingInfo?.signingCertificateHistory
            ?.joinToString { it.toCharsString() }.orEmpty()}
            splitNames=${this.splitNames?.contentToString()}
            splitRevisionCodes=${this.splitRevisionCodes?.contentToString()}
            targetOverlayableName=${this.targetOverlayableName}
+65 −0
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.pm.parsing

import android.content.pm.PackageManager
import android.content.pm.PackageParser
import android.platform.test.annotations.Postsubmit
import com.android.server.pm.PackageManagerService
import org.junit.Test

/**
 * This test parses all the system APKs on the device image to ensure that they succeed.
 *
 * Any invalid APKs should be removed from the device or marked as skipped through any mechanism
 * for ignoring packages.
 *
 * This test must run on deferred postsubmit. Targeted presubmit will not catch errors fast enough,
 * and the low failure rate does not warrant global presubmit.
 */
@Postsubmit
class SystemPartitionParseTest {

    private val APKS = PackageManagerService.SYSTEM_PARTITIONS
            .flatMap { listOfNotNull(it.appFolder, it.privAppFolder, it.overlayFolder) }
            .flatMap {
                it.walkTopDown()
                        .filter { it.name.endsWith(".apk") }
                        .toList()
            }
            .distinct()

    private val parser = PackageParser2.forParsingFileWithDefaults()

    @Test
    fun verify() {
        val exceptions = APKS
                .map {
                    runCatching {
                        parser.parsePackage(it, PackageParser.PARSE_IS_SYSTEM_DIR, false)
                    }
                }
                .mapNotNull { it.exceptionOrNull() }
                .filterNot { (it as? PackageParser.PackageParserException)?.error ==
                        PackageManager.INSTALL_PARSE_FAILED_SKIPPED }

        if (exceptions.isEmpty()) return

        throw AssertionError("verify failed with ${exceptions.size} errors:\n" +
                exceptions.joinToString(separator = "\n") { it.message.orEmpty() })
    }
}