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

Commit dbb43b32 authored by Samiul Islam's avatar Samiul Islam Committed by Android (Google) Code Review
Browse files

Merge changes from topic "fail-to-bind" into main

* changes:
  Add support for parsing multiple signer for Static Libraries
  Resolve SDK dependency asynchronously before install
parents 9d9cc46f 92e31e38
Loading
Loading
Loading
Loading
+53 −13
Original line number Diff line number Diff line
@@ -38,6 +38,7 @@ import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.AttributeSet;
import android.util.EmptyArray;
import android.util.Pair;
import android.util.Slog;

@@ -565,10 +566,7 @@ public class ApkLiteParseUtils {
                                    usesSdkLibrariesVersionsMajor, usesSdkLibVersionMajor,
                                    /*allowDuplicates=*/ true);

                            // We allow ":" delimiters in the SHA declaration as this is the format
                            // emitted by the certtool making it easy for developers to copy/paste.
                            // TODO(372862145): Add test for this replacement
                            usesSdkCertDigest = usesSdkCertDigest.replace(":", "").toLowerCase();
                            usesSdkCertDigest = normalizeCertDigest(usesSdkCertDigest);

                            if ("".equals(usesSdkCertDigest)) {
                                // Test-only uses-sdk-library empty certificate digest override.
@@ -618,18 +616,23 @@ public class ApkLiteParseUtils {
                                    usesStaticLibrariesVersions, usesStaticLibVersion,
                                    /*allowDuplicates=*/ true);

                            // We allow ":" delimiters in the SHA declaration as this is the format
                            // emitted by the certtool making it easy for developers to copy/paste.
                            // TODO(372862145): Add test for this replacement
                            usesStaticLibCertDigest =
                                    usesStaticLibCertDigest.replace(":", "").toLowerCase();
                            usesStaticLibCertDigest = normalizeCertDigest(usesStaticLibCertDigest);

                            ParseResult<String[]> certResult =
                                    parseAdditionalCertificates(input, parser);
                            if (certResult.isError()) {
                                return input.error(certResult);
                            }
                            String[] additionalCertSha256Digests = certResult.getResult();
                            String[] certSha256Digests =
                                    new String[additionalCertSha256Digests.length + 1];
                            certSha256Digests[0] = usesStaticLibCertDigest;
                            System.arraycopy(additionalCertSha256Digests, 0, certSha256Digests,
                                    1, additionalCertSha256Digests.length);

                            // TODO(372862145): Add support for multiple signer for app targeting
                            //  O-MR1
                            usesStaticLibrariesCertDigests = ArrayUtils.appendElement(
                                    String[].class, usesStaticLibrariesCertDigests,
                                    new String[]{usesStaticLibCertDigest},
                                    /*allowDuplicates=*/ true);
                                    certSha256Digests, /*allowDuplicates=*/ true);
                            break;
                        case TAG_SDK_LIBRARY:
                            isSdkLibrary = true;
@@ -809,6 +812,43 @@ public class ApkLiteParseUtils {
                        declaredLibraries));
    }

    private static ParseResult<String[]> parseAdditionalCertificates(ParseInput input,
            XmlResourceParser parser) throws XmlPullParserException, IOException {
        String[] certSha256Digests = EmptyArray.STRING;
        final int depth = parser.getDepth();
        int type;
        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
                && (type != XmlPullParser.END_TAG
                || parser.getDepth() > depth)) {
            if (type != XmlPullParser.START_TAG) {
                continue;
            }
            final String nodeName = parser.getName();
            if (nodeName.equals("additional-certificate")) {
                String certSha256Digest = parser.getAttributeValue(
                        ANDROID_RES_NAMESPACE, "certDigest");
                if (TextUtils.isEmpty(certSha256Digest)) {
                    return input.error("Bad additional-certificate declaration with empty"
                            + " certDigest:" + certSha256Digest);
                }

                certSha256Digest = normalizeCertDigest(certSha256Digest);
                certSha256Digests = ArrayUtils.appendElement(String.class,
                        certSha256Digests, certSha256Digest);
            }
        }

        return input.success(certSha256Digests);
    }

    /**
     * We allow ":" delimiters in the SHA declaration as this is the format emitted by the
     * certtool making it easy for developers to copy/paste.
     */
    private static String normalizeCertDigest(String certDigest) {
        return certDigest.replace(":", "").toLowerCase();
    }

    private static boolean isDeviceAdminReceiver(
            XmlResourceParser parser, boolean applicationHasBindDeviceAdminPermission)
            throws XmlPullParserException, IOException {
+1 −0
Original line number Diff line number Diff line
@@ -151,6 +151,7 @@ android_test {
        ":HelloWorldUsingSdk1And2",
        ":HelloWorldUsingSdkMalformedNegativeVersion",
        ":CtsStaticSharedLibConsumerApp1",
        ":CtsStaticSharedLibConsumerApp3",
    ],
}

+2 −0
Original line number Diff line number Diff line
@@ -41,6 +41,8 @@
            value="/data/local/tmp/tests/coretests/pm/HelloWorldSdk1.apk"/>
        <option name="push-file" key="CtsStaticSharedLibConsumerApp1.apk"
            value="/data/local/tmp/tests/coretests/pm/CtsStaticSharedLibConsumerApp1.apk"/>
        <option name="push-file" key="CtsStaticSharedLibConsumerApp3.apk"
            value="/data/local/tmp/tests/coretests/pm/CtsStaticSharedLibConsumerApp3.apk"/>
    </target_preparer>

    <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
+34 −18
Original line number Diff line number Diff line
@@ -72,6 +72,12 @@ public class ApkLiteParseUtilsTest {
    private static final String TEST_APP_USING_SDK_MALFORMED_VERSION =
            "HelloWorldUsingSdkMalformedNegativeVersion.apk";
    private static final String TEST_APP_USING_STATIC_LIB = "CtsStaticSharedLibConsumerApp1.apk";
    private static final String TEST_APP_USING_STATIC_LIB_TWO_CERTS =
            "CtsStaticSharedLibConsumerApp3.apk";
    private static final String STATIC_LIB_CERT_1 =
            "70fbd440503ec0bf41f3f21fcc83ffd39880133c27deb0945ed677c6f31d72fb";
    private static final String STATIC_LIB_CERT_2 =
            "e49582ff3a0aa4c5589fc5feaac6b7d6e757199dd0c6742df7bf37c2ffef95f5";
    private static final String TEST_SDK1 = "HelloWorldSdk1.apk";
    private static final String TEST_SDK1_PACKAGE = "com.test.sdk1_1";
    private static final String TEST_SDK1_NAME = "com.test.sdk1";
@@ -86,7 +92,7 @@ public class ApkLiteParseUtilsTest {

    @Before
    public void setUp() throws IOException {
        mTmpDir = mTemporaryFolder.newFolder("DexMetadataHelperTest");
        mTmpDir = mTemporaryFolder.newFolder("ApkLiteParseUtilsTest");
    }

    @After
@@ -108,9 +114,8 @@ public class ApkLiteParseUtilsTest {
        assertThat(baseApk.getUsesSdkLibrariesVersionsMajor()).asList().containsExactly(
                TEST_SDK1_VERSION, TEST_SDK2_VERSION
        );
        for (String[] certDigests: baseApk.getUsesSdkLibrariesCertDigests()) {
            assertThat(certDigests).asList().containsExactly("");
        }
        String[][] expectedCerts = {{""}, {""}};
        assertThat(baseApk.getUsesSdkLibrariesCertDigests()).isEqualTo(expectedCerts);
    }

    @SuppressLint("CheckResult")
@@ -126,18 +131,13 @@ public class ApkLiteParseUtilsTest {
        ApkLite baseApk = result.getResult();

        String[][] liteCerts = baseApk.getUsesSdkLibrariesCertDigests();
        assertThat(liteCerts).isNotNull();
        for (String[] certDigests: liteCerts) {
            assertThat(certDigests).asList().containsExactly(certDigest);
        }
        String[][] expectedCerts = {{certDigest}, {certDigest}};
        assertThat(liteCerts).isEqualTo(expectedCerts);

        // Same for package parser
        AndroidPackage pkg = mPackageParser2.parsePackage(apkFile, 0, true).hideAsFinal();
        String[][] pkgCerts = pkg.getUsesSdkLibrariesCertDigests();
        assertThat(pkgCerts).isNotNull();
        for (int i = 0; i < liteCerts.length; i++) {
            assertThat(liteCerts[i]).isEqualTo(pkgCerts[i]);
        }
        assertThat(liteCerts).isEqualTo(pkgCerts);
    }


@@ -160,9 +160,7 @@ public class ApkLiteParseUtilsTest {

        String[][] liteCerts = baseApk.getUsesSdkLibrariesCertDigests();
        String[][] pkgCerts = pkg.getUsesSdkLibrariesCertDigests();
        for (int i = 0; i < liteCerts.length; i++) {
            assertThat(liteCerts[i]).isEqualTo(pkgCerts[i]);
        }
        assertThat(liteCerts).isEqualTo(pkgCerts);
    }

    @SuppressLint("CheckResult")
@@ -184,9 +182,27 @@ public class ApkLiteParseUtilsTest {

        String[][] liteCerts = baseApk.getUsesStaticLibrariesCertDigests();
        String[][] pkgCerts = pkg.getUsesStaticLibrariesCertDigests();
        for (int i = 0; i < liteCerts.length; i++) {
            assertThat(liteCerts[i]).isEqualTo(pkgCerts[i]);
        assertThat(liteCerts).isEqualTo(pkgCerts);
    }

    @Test
    public void testParseApkLite_getUsesStaticLibrary_twoCerts()
            throws Exception {
        File apkFile = copyApkToTmpDir(TEST_APP_USING_STATIC_LIB_TWO_CERTS);
        ParseResult<ApkLite> result = ApkLiteParseUtils
                .parseApkLite(ParseTypeImpl.forDefaultParsing().reset(), apkFile, 0);
        assertThat(result.isError()).isFalse();
        ApkLite baseApk = result.getResult();

        // There are two certs.
        String[][] expectedCerts = {{STATIC_LIB_CERT_1, STATIC_LIB_CERT_2}};
        String[][] liteCerts = baseApk.getUsesStaticLibrariesCertDigests();
        assertThat(liteCerts).isEqualTo(expectedCerts);

        // And they are same as package parser.
        AndroidPackage pkg = mPackageParser2.parsePackage(apkFile, 0, true).hideAsFinal();
        String[][] pkgCerts = pkg.getUsesStaticLibrariesCertDigests();
        assertThat(liteCerts).isEqualTo(pkgCerts);
    }

    @SuppressLint("CheckResult")
+67 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 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;

import static android.content.pm.PackageManager.INSTALL_FAILED_MISSING_SHARED_LIBRARY;

import android.content.pm.SharedLibraryInfo;
import android.content.pm.parsing.PackageLite;
import android.os.OutcomeReceiver;

import java.util.List;

/**
 * Helper class to interact with SDK Dependency Installer service.
 */
public class InstallDependencyHelper {
    private final SharedLibrariesImpl mSharedLibraries;

    InstallDependencyHelper(SharedLibrariesImpl sharedLibraries) {
        mSharedLibraries = sharedLibraries;
    }

    void resolveLibraryDependenciesIfNeeded(PackageLite pkg,
            OutcomeReceiver<Void, PackageManagerException> callback) {
        final List<SharedLibraryInfo> missing;
        try {
            missing = mSharedLibraries.collectMissingSharedLibraryInfos(pkg);
        } catch (PackageManagerException e) {
            callback.onError(e);
            return;
        }

        if (missing.isEmpty()) {
            // No need for dependency resolution. Move to installation directly.
            callback.onResult(null);
            return;
        }

        try {
            bindToDependencyInstaller();
        } catch (Exception e) {
            PackageManagerException pe = new PackageManagerException(
                    INSTALL_FAILED_MISSING_SHARED_LIBRARY, e.getMessage());
            callback.onError(pe);
        }
    }

    private void bindToDependencyInstaller() {
        throw new IllegalStateException("Failed to bind to Dependency Installer");
    }


}
Loading