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

Commit 156cb611 authored by Winson Chiu's avatar Winson Chiu Committed by Android (Google) Code Review
Browse files

Merge "Move package parsing to services.jar"

parents 1c283261 efbb3196
Loading
Loading
Loading
Loading
+5 −1
Original line number Diff line number Diff line
@@ -10,7 +10,10 @@ package {
android_test {
    name: "PackageManagerPerfTests",

    srcs: ["src/**/*.java"],
    srcs: [
        "src/**/*.java",
        "src/**/*.kt",
    ],

    static_libs: [
        "platform-compat-test-rules",
@@ -21,6 +24,7 @@ android_test {
        "apct-perftests-utils",
        "collector-device-lib-platform",
        "cts-install-lib-java",
        "services.core",
    ],

    libs: ["android.test.base"],
+18 −9
Original line number Diff line number Diff line
/*
 * Copyright (C) 2020 The Android Open Source Project
 * Copyright (C) 2022 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.
@@ -19,9 +19,6 @@ package android.os
import android.content.pm.PackageParser
import android.content.pm.PackageParserCacheHelper.ReadHelper
import android.content.pm.PackageParserCacheHelper.WriteHelper
import android.content.pm.parsing.ParsingPackageImpl
import android.content.pm.parsing.ParsingPackageRead
import android.content.pm.parsing.ParsingPackageUtils
import android.content.pm.parsing.result.ParseInput
import android.content.pm.parsing.result.ParseTypeImpl
import android.content.res.TypedArray
@@ -29,6 +26,8 @@ import android.perftests.utils.BenchmarkState
import android.perftests.utils.PerfStatusReporter
import androidx.test.filters.LargeTest
import com.android.internal.util.ConcurrentUtils
import com.android.server.pm.pkg.parsing.ParsingPackageImpl
import com.android.server.pm.pkg.parsing.ParsingPackageUtils
import libcore.io.IoUtils
import org.junit.Rule
import org.junit.Test
@@ -42,7 +41,7 @@ import java.util.concurrent.TimeUnit

@LargeTest
@RunWith(Parameterized::class)
class PackageParsingPerfTest {
public class PackageParsingPerfTest {

    companion object {
        private const val PARALLEL_QUEUE_CAPACITY = 10
@@ -196,8 +195,12 @@ class PackageParsingPerfTest {
            // For testing, just disable enforcement to avoid hooking up to compat framework
            ParseTypeImpl(ParseInput.Callback { _, _, _ -> false })
        }
        val parser = ParsingPackageUtils(false, null, null, emptyList(),
            object : ParsingPackageUtils.Callback {
        val parser = ParsingPackageUtils(false,
            null,
            null,
            emptyList(),
            object :
                ParsingPackageUtils.Callback {
                override fun hasFeature(feature: String) = true

                override fun startParsingPackage(
@@ -206,7 +209,12 @@ class PackageParsingPerfTest {
                    path: String,
                    manifestArray: TypedArray,
                    isCoreApp: Boolean
                ) = ParsingPackageImpl(packageName, baseApkPath, path, manifestArray)
                ) = ParsingPackageImpl(
                    packageName,
                    baseApkPath,
                    path,
                    manifestArray
                )
            })

        override fun parseImpl(file: File) =
@@ -268,6 +276,7 @@ class PackageParsingPerfTest {
     * Re-implementation of the server side PackageCacher, as it's inaccessible here.
     */
    class PackageCacher2(cacheDir: File) : PackageCacher<ParsingPackageImpl>(cacheDir) {
        override fun fromParcel(parcel: Parcel) = ParsingPackageImpl(parcel)
        override fun fromParcel(parcel: Parcel) =
            ParsingPackageImpl(parcel)
    }
}
+1 −37
Original line number Diff line number Diff line
@@ -62,6 +62,7 @@ import android.content.pm.PackageInfo;
import android.content.pm.PackageInstaller;
import android.content.pm.PackageItemInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageParser;
import android.content.pm.ParceledListSlice;
import android.content.pm.PermissionGroupInfo;
import android.content.pm.PermissionInfo;
@@ -73,12 +74,6 @@ import android.content.pm.SuspendDialogInfo;
import android.content.pm.VerifierDeviceIdentity;
import android.content.pm.VersionedPackage;
import android.content.pm.dex.ArtManager;
import android.content.pm.parsing.PackageInfoWithoutStateUtils;
import android.content.pm.parsing.ParsingPackage;
import android.content.pm.parsing.ParsingPackageUtils;
import android.content.pm.parsing.result.ParseInput;
import android.content.pm.parsing.result.ParseResult;
import android.content.pm.parsing.result.ParseTypeImpl;
import android.content.pm.pkg.FrameworkPackageUserState;
import android.content.res.Configuration;
import android.content.res.Resources;
@@ -2335,37 +2330,6 @@ public class ApplicationPackageManager extends PackageManager {
        return info.loadLabel(this);
    }

    @Nullable
    public PackageInfo getPackageArchiveInfo(@NonNull String archiveFilePath, int flags) {
        return getPackageArchiveInfo(archiveFilePath, PackageInfoFlags.of(flags));
    }

    @Nullable
    public PackageInfo getPackageArchiveInfo(@NonNull String archiveFilePath,
            PackageInfoFlags flags) {
        long flagsBits = flags.getValue();
        if ((flagsBits & (PackageManager.MATCH_DIRECT_BOOT_UNAWARE
                | PackageManager.MATCH_DIRECT_BOOT_AWARE)) == 0) {
            // Caller expressed no opinion about what encryption
            // aware/unaware components they want to see, so match both
            flagsBits |= PackageManager.MATCH_DIRECT_BOOT_AWARE
                    | PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
        }

        boolean collectCertificates = (flagsBits & PackageManager.GET_SIGNATURES) != 0
                || (flagsBits & PackageManager.GET_SIGNING_CERTIFICATES) != 0;

        ParseInput input = ParseTypeImpl.forParsingWithoutPlatformCompat().reset();
        ParseResult<ParsingPackage> result = ParsingPackageUtils.parseDefault(input,
                new File(archiveFilePath), 0, getPermissionManager().getSplitPermissions(),
                collectCertificates);
        if (result.isError()) {
            return null;
        }
        return PackageInfoWithoutStateUtils.generate(result.getResult(), null, flagsBits, 0, 0,
                null, FrameworkPackageUserState.DEFAULT, UserHandle.getCallingUserId());
    }

    @Override
    public int installExistingPackage(String packageName) throws NameNotFoundException {
        return installExistingPackage(packageName, INSTALL_REASON_UNKNOWN);
+26 −4
Original line number Diff line number Diff line
@@ -50,6 +50,7 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.content.IntentSender;
import android.content.pm.dex.ArtManager;
import android.content.pm.pkg.FrameworkPackageUserState;
import android.content.pm.verify.domain.DomainVerificationManager;
import android.content.res.Configuration;
import android.content.res.Resources;
@@ -88,6 +89,7 @@ import com.android.internal.util.DataClass;

import dalvik.system.VMRuntime;

import java.io.File;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.security.cert.Certificate;
@@ -7891,8 +7893,7 @@ public abstract class PackageManager {
    @Deprecated
    @Nullable
    public PackageInfo getPackageArchiveInfo(@NonNull String archiveFilePath, int flags) {
        throw new UnsupportedOperationException(
                "getPackageArchiveInfo() not implemented in subclass");
        return getPackageArchiveInfo(archiveFilePath, PackageInfoFlags.of(flags));
    }

    /**
@@ -7901,8 +7902,29 @@ public abstract class PackageManager {
    @Nullable
    public PackageInfo getPackageArchiveInfo(@NonNull String archiveFilePath,
            @NonNull PackageInfoFlags flags) {
        throw new UnsupportedOperationException(
                "getPackageArchiveInfo() not implemented in subclass");
        long flagsBits = flags.getValue();
        final PackageParser parser = new PackageParser();
        parser.setCallback(new PackageParser.CallbackImpl(this));
        final File apkFile = new File(archiveFilePath);
        try {
            if ((flagsBits & (MATCH_DIRECT_BOOT_UNAWARE | MATCH_DIRECT_BOOT_AWARE)) != 0) {
                // Caller expressed an explicit opinion about what encryption
                // aware/unaware components they want to see, so fall through and
                // give them what they want
            } else {
                // Caller expressed no opinion, so match everything
                flagsBits |= MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE;
            }

            PackageParser.Package pkg = parser.parsePackage(apkFile, 0, false);
            if ((flagsBits & GET_SIGNATURES) != 0) {
                PackageParser.collectCertificates(pkg, false /* skipVerify */);
            }
            return PackageParser.generatePackageInfo(pkg, null, (int) flagsBits, 0, 0, null,
                    FrameworkPackageUserState.DEFAULT);
        } catch (PackageParser.PackageParserException e) {
            return null;
        }
    }

    /**
+206 −13
Original line number Diff line number Diff line
/*
 * Copyright (C) 2007 The Android Open Source Project
 * Copyright (C) 2022 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.
@@ -37,6 +37,8 @@ import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_INCONSISTEN
import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_NOT_APK;
import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION;
import static android.content.pm.PackageManager.MATCH_DISABLED_COMPONENTS;
import static android.content.pm.PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS;
import static android.os.Build.VERSION_CODES.O;
import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_UNSPECIFIED;
@@ -55,11 +57,9 @@ import android.content.ComponentName;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.overlay.OverlayPaths;
import android.content.pm.parsing.ParsingPackageUtils;
import android.content.pm.pkg.FrameworkPackageUserState;
import android.content.pm.pkg.PackageUserStateUtils;
import android.content.pm.parsing.result.ParseResult;
import android.content.pm.parsing.result.ParseTypeImpl;
import android.content.pm.pkg.FrameworkPackageUserState;
import android.content.res.ApkAssets;
import android.content.res.AssetManager;
import android.content.res.Configuration;
@@ -68,6 +68,7 @@ import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
import android.os.Build;
import android.os.Bundle;
import android.os.Debug;
import android.os.FileUtils;
import android.os.Parcel;
import android.os.Parcelable;
@@ -83,6 +84,7 @@ import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.AttributeSet;
import android.util.Base64;
import android.util.DebugUtils;
import android.util.DisplayMetrics;
import android.util.IntArray;
import android.util.Log;
@@ -128,6 +130,7 @@ import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;

@@ -148,7 +151,7 @@ import java.util.UUID;
 * </ul>
 *
 * @deprecated This class is mostly unused and no new changes should be added to it. Use
 * {@link android.content.pm.parsing.ParsingPackageUtils} and related parsing v2 infrastructure in
 * ParsingPackageUtils and related parsing v2 infrastructure in
 * the core/services parsing subpackages. Or for a quick parse of a provided APK, use
 * {@link PackageManager#getPackageArchiveInfo(String, int)}.
 *
@@ -655,7 +658,7 @@ public class PackageParser {

        // If available for the target user, or trying to match uninstalled packages and it's
        // a system app.
        return PackageUserStateUtils.isAvailable(state, flags)
        return isAvailable(state, flags)
                || (appInfo != null && appInfo.isSystemApp()
                        && ((flags & PackageManager.MATCH_KNOWN_PACKAGES) != 0
                        || (flags & PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS) != 0));
@@ -765,7 +768,7 @@ public class PackageParser {
                final ActivityInfo[] res = new ActivityInfo[N];
                for (int i = 0; i < N; i++) {
                    final Activity a = p.activities.get(i);
                    if (PackageUserStateUtils.isMatch(state, a.info, flags)) {
                    if (isMatch(state, a.info, flags)) {
                        if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(a.className)) {
                            continue;
                        }
@@ -782,7 +785,7 @@ public class PackageParser {
                final ActivityInfo[] res = new ActivityInfo[N];
                for (int i = 0; i < N; i++) {
                    final Activity a = p.receivers.get(i);
                    if (PackageUserStateUtils.isMatch(state, a.info, flags)) {
                    if (isMatch(state, a.info, flags)) {
                        res[num++] = generateActivityInfo(a, flags, state, userId);
                    }
                }
@@ -796,7 +799,7 @@ public class PackageParser {
                final ServiceInfo[] res = new ServiceInfo[N];
                for (int i = 0; i < N; i++) {
                    final Service s = p.services.get(i);
                    if (PackageUserStateUtils.isMatch(state, s.info, flags)) {
                    if (isMatch(state, s.info, flags)) {
                        res[num++] = generateServiceInfo(s, flags, state, userId);
                    }
                }
@@ -810,7 +813,7 @@ public class PackageParser {
                final ProviderInfo[] res = new ProviderInfo[N];
                for (int i = 0; i < N; i++) {
                    final Provider pr = p.providers.get(i);
                    if (PackageUserStateUtils.isMatch(state, pr.info, flags)) {
                    if (isMatch(state, pr.info, flags)) {
                        res[num++] = generateProviderInfo(pr, flags, state, userId);
                    }
                }
@@ -7428,7 +7431,7 @@ public class PackageParser {
            mCompileSdkVersionCodename = dest.readString();
            mUpgradeKeySets = (ArraySet<String>) dest.readArraySet(boot);

            mKeySetMapping = ParsingPackageUtils.readKeySetMapping(dest);
            mKeySetMapping = readKeySetMapping(dest);

            cpuAbiOverride = dest.readString();
            use32bitAbi = (dest.readInt() == 1);
@@ -7554,7 +7557,7 @@ public class PackageParser {
            dest.writeInt(mCompileSdkVersion);
            dest.writeString(mCompileSdkVersionCodename);
            dest.writeArraySet(mUpgradeKeySets);
            ParsingPackageUtils.writeKeySetMapping(dest, mKeySetMapping);
            writeKeySetMapping(dest, mKeySetMapping);
            dest.writeString(cpuAbiOverride);
            dest.writeInt(use32bitAbi ? 1 : 0);
            dest.writeByteArray(restrictUpdateHash);
@@ -7977,7 +7980,7 @@ public class PackageParser {
        if (ai.category == ApplicationInfo.CATEGORY_UNDEFINED) {
            ai.category = FallbackCategoryProvider.getFallbackCategory(ai.packageName);
        }
        ai.seInfoUser = SELinuxUtil.getSeinfoUser(state);
        ai.seInfoUser = getSeinfoUser(state);
        final OverlayPaths overlayPaths = state.getAllOverlayPaths();
        if (overlayPaths != null) {
            ai.resourceDirs = overlayPaths.getResourceDirs().toArray(new String[0]);
@@ -9074,4 +9077,194 @@ public class PackageParser {
            return mCachedSplitApks[0][0];
        }
    }



    public static boolean isMatch(@NonNull FrameworkPackageUserState state,
            ComponentInfo componentInfo, long flags) {
        return isMatch(state, componentInfo.applicationInfo.isSystemApp(),
                componentInfo.applicationInfo.enabled, componentInfo.enabled,
                componentInfo.directBootAware, componentInfo.name, flags);
    }

    public static boolean isMatch(@NonNull FrameworkPackageUserState state, boolean isSystem,
            boolean isPackageEnabled, ComponentInfo component, long flags) {
        return isMatch(state, isSystem, isPackageEnabled, component.isEnabled(),
                component.directBootAware, component.name, flags);
    }

    /**
     * Test if the given component is considered installed, enabled and a match for the given
     * flags.
     *
     * <p>
     * Expects at least one of {@link PackageManager#MATCH_DIRECT_BOOT_AWARE} and {@link
     * PackageManager#MATCH_DIRECT_BOOT_UNAWARE} are specified in {@code flags}.
     * </p>
     */
    public static boolean isMatch(@NonNull FrameworkPackageUserState state, boolean isSystem,
            boolean isPackageEnabled, boolean isComponentEnabled,
            boolean isComponentDirectBootAware, String componentName, long flags) {
        final boolean matchUninstalled = (flags & PackageManager.MATCH_KNOWN_PACKAGES) != 0;
        if (!isAvailable(state, flags) && !(isSystem && matchUninstalled)) {
            return reportIfDebug(false, flags);
        }

        if (!isEnabled(state, isPackageEnabled, isComponentEnabled, componentName, flags)) {
            return reportIfDebug(false, flags);
        }

        if ((flags & PackageManager.MATCH_SYSTEM_ONLY) != 0) {
            if (!isSystem) {
                return reportIfDebug(false, flags);
            }
        }

        final boolean matchesUnaware = ((flags & PackageManager.MATCH_DIRECT_BOOT_UNAWARE) != 0)
                && !isComponentDirectBootAware;
        final boolean matchesAware = ((flags & PackageManager.MATCH_DIRECT_BOOT_AWARE) != 0)
                && isComponentDirectBootAware;
        return reportIfDebug(matchesUnaware || matchesAware, flags);
    }

    public static boolean isAvailable(@NonNull FrameworkPackageUserState state, long flags) {
        // True if it is installed for this user and it is not hidden. If it is hidden,
        // still return true if the caller requested MATCH_UNINSTALLED_PACKAGES
        final boolean matchAnyUser = (flags & PackageManager.MATCH_ANY_USER) != 0;
        final boolean matchUninstalled = (flags & PackageManager.MATCH_UNINSTALLED_PACKAGES) != 0;
        return matchAnyUser
                || (state.isInstalled()
                && (!state.isHidden() || matchUninstalled));
    }

    public static boolean reportIfDebug(boolean result, long flags) {
        if (DEBUG_PARSER && !result) {
            Slog.i(TAG, "No match!; flags: "
                    + DebugUtils.flagsToString(PackageManager.class, "MATCH_", flags) + " "
                    + Debug.getCaller());
        }
        return result;
    }

    public static boolean isEnabled(@NonNull FrameworkPackageUserState state, ComponentInfo componentInfo,
            long flags) {
        return isEnabled(state, componentInfo.applicationInfo.enabled, componentInfo.enabled,
                componentInfo.name, flags);
    }

    public static boolean isEnabled(@NonNull FrameworkPackageUserState state, boolean isPackageEnabled,
            ComponentInfo parsedComponent, long flags) {
        return isEnabled(state, isPackageEnabled, parsedComponent.isEnabled(),
                parsedComponent.name, flags);
    }

    /**
     * Test if the given component is considered enabled.
     */
    public static boolean isEnabled(@NonNull FrameworkPackageUserState state,
            boolean isPackageEnabled, boolean isComponentEnabled, String componentName,
            long flags) {
        if ((flags & MATCH_DISABLED_COMPONENTS) != 0) {
            return true;
        }

        // First check if the overall package is disabled; if the package is
        // enabled then fall through to check specific component
        switch (state.getEnabledState()) {
            case PackageManager.COMPONENT_ENABLED_STATE_DISABLED:
            case PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER:
                return false;
            case PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED:
                if ((flags & MATCH_DISABLED_UNTIL_USED_COMPONENTS) == 0) {
                    return false;
                }
                // fallthrough
            case PackageManager.COMPONENT_ENABLED_STATE_DEFAULT:
                if (!isPackageEnabled) {
                    return false;
                }
                // fallthrough
            case PackageManager.COMPONENT_ENABLED_STATE_ENABLED:
                break;
        }

        // Check if component has explicit state before falling through to
        // the manifest default
        if (state.isComponentEnabled(componentName)) {
            return true;
        } else if (state.isComponentDisabled(componentName)) {
            return false;
        }

        return isComponentEnabled;
    }

    /**
     * Writes the keyset mapping to the provided package. {@code null} mappings are permitted.
     */
    public static void writeKeySetMapping(@NonNull Parcel dest,
            @NonNull Map<String, ArraySet<PublicKey>> keySetMapping) {
        if (keySetMapping == null) {
            dest.writeInt(-1);
            return;
        }

        final int N = keySetMapping.size();
        dest.writeInt(N);

        for (String key : keySetMapping.keySet()) {
            dest.writeString(key);
            ArraySet<PublicKey> keys = keySetMapping.get(key);
            if (keys == null) {
                dest.writeInt(-1);
                continue;
            }

            final int M = keys.size();
            dest.writeInt(M);
            for (int j = 0; j < M; j++) {
                dest.writeSerializable(keys.valueAt(j));
            }
        }
    }

    /**
     * Reads a keyset mapping from the given parcel at the given data position. May return
     * {@code null} if the serialized mapping was {@code null}.
     */
    @NonNull
    public static ArrayMap<String, ArraySet<PublicKey>> readKeySetMapping(@NonNull Parcel in) {
        final int N = in.readInt();
        if (N == -1) {
            return null;
        }

        ArrayMap<String, ArraySet<PublicKey>> keySetMapping = new ArrayMap<>();
        for (int i = 0; i < N; ++i) {
            String key = in.readString();
            final int M = in.readInt();
            if (M == -1) {
                keySetMapping.put(key, null);
                continue;
            }

            ArraySet<PublicKey> keys = new ArraySet<>(M);
            for (int j = 0; j < M; ++j) {
                PublicKey pk =
                        in.readSerializable(PublicKey.class.getClassLoader(), PublicKey.class);
                keys.add(pk);
            }

            keySetMapping.put(key, keys);
        }

        return keySetMapping;
    }

    public static String getSeinfoUser(FrameworkPackageUserState userState) {
        if (userState.isInstantApp()) {
            return ":ephemeralapp:complete";
        }
        return ":complete";
    }
}
Loading