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

Commit e7753e08 authored by Nicolas Geoffray's avatar Nicolas Geoffray Committed by Gerrit Code Review
Browse files

Merge "Start using shared libraries class loader."

parents a920b9c8 972b39e4
Loading
Loading
Loading
Loading
+16 −5
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@ import com.android.internal.os.ClassLoaderFactory;
import dalvik.system.PathClassLoader;

import java.util.Collection;
import java.util.List;

/** @hide */
public class ApplicationLoaders {
@@ -38,15 +39,25 @@ public class ApplicationLoaders {
    ClassLoader getClassLoader(String zip, int targetSdkVersion, boolean isBundled,
                               String librarySearchPath, String libraryPermittedPath,
                               ClassLoader parent, String classLoaderName) {
        return getClassLoaderWithSharedLibraries(zip, targetSdkVersion, isBundled,
                              librarySearchPath, libraryPermittedPath, parent, classLoaderName,
                              null);
    }

    ClassLoader getClassLoaderWithSharedLibraries(
            String zip, int targetSdkVersion, boolean isBundled,
            String librarySearchPath, String libraryPermittedPath,
            ClassLoader parent, String classLoaderName,
            List<ClassLoader> sharedLibraries) {
        // For normal usage the cache key used is the same as the zip path.
        return getClassLoader(zip, targetSdkVersion, isBundled, librarySearchPath,
                              libraryPermittedPath, parent, zip, classLoaderName);
                              libraryPermittedPath, parent, zip, classLoaderName, sharedLibraries);
    }

    private ClassLoader getClassLoader(String zip, int targetSdkVersion, boolean isBundled,
                                       String librarySearchPath, String libraryPermittedPath,
                                       ClassLoader parent, String cacheKey,
                                       String classLoaderName) {
                                       String classLoaderName, List<ClassLoader> sharedLibraries) {
        /*
         * This is the parent we use if they pass "null" in.  In theory
         * this should be the "system" class loader; in practice we
@@ -75,7 +86,7 @@ public class ApplicationLoaders {

                ClassLoader classloader = ClassLoaderFactory.createClassLoader(
                        zip,  librarySearchPath, libraryPermittedPath, parent,
                        targetSdkVersion, isBundled, classLoaderName);
                        targetSdkVersion, isBundled, classLoaderName, sharedLibraries);

                Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);

@@ -90,7 +101,7 @@ public class ApplicationLoaders {

            Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, zip);
            ClassLoader loader = ClassLoaderFactory.createClassLoader(
                    zip, null, parent, classLoaderName);
                    zip, null, parent, classLoaderName, sharedLibraries);
            Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
            return loader;
        }
@@ -110,7 +121,7 @@ public class ApplicationLoaders {
        // The cache key is passed separately to enable the stub WebView to be cached under the
        // stub's APK path, when the actual package path is the donor APK.
        return getClassLoader(packagePath, Build.VERSION.SDK_INT, false, libsPath, null, null,
                              cacheKey, null /* classLoaderName */);
                              cacheKey, null /* classLoaderName */, null /* sharedLibraries */);
    }

    /**
+77 −8
Original line number Diff line number Diff line
@@ -29,6 +29,7 @@ import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.SharedLibraryInfo;
import android.content.pm.dex.ArtManager;
import android.content.pm.split.SplitDependencyLoader;
import android.content.res.AssetManager;
@@ -70,8 +71,10 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Enumeration;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;

final class IntentReceiverLeaked extends AndroidRuntimeException {
    @UnsupportedAppUsage
@@ -397,6 +400,24 @@ public final class LoadedApk {
        makePaths(activityThread, false, aInfo, outZipPaths, null);
    }

    private static void appendSharedLibrariesLibPathsIfNeeded(
            List<SharedLibraryInfo> sharedLibraries, ApplicationInfo aInfo,
            Set<String> outSeenPaths,
            List<String> outLibPaths) {
        if (sharedLibraries == null) {
            return;
        }
        for (SharedLibraryInfo lib : sharedLibraries) {
            List<String> paths = lib.getAllCodePaths();
            outSeenPaths.addAll(paths);
            for (String path : paths) {
                appendApkLibPathIfNeeded(path, aInfo, outLibPaths);
            }
            appendSharedLibrariesLibPathsIfNeeded(
                    lib.getDependencies(), aInfo, outSeenPaths, outLibPaths);
        }
    }

    public static void makePaths(ActivityThread activityThread,
                                 boolean isBundledApp,
                                 ApplicationInfo aInfo,
@@ -404,7 +425,6 @@ public final class LoadedApk {
                                 List<String> outLibPaths) {
        final String appDir = aInfo.sourceDir;
        final String libDir = aInfo.nativeLibraryDir;
        final String[] sharedLibraries = aInfo.sharedLibraryFiles;

        outZipPaths.clear();
        outZipPaths.add(appDir);
@@ -499,11 +519,19 @@ public final class LoadedApk {
            }
        }

        // Prepend the shared libraries, maintaining their original order where possible.
        if (sharedLibraries != null) {
        // Add the shared libraries native paths. The dex files in shared libraries will
        // be resolved through shared library loaders, which are setup later.
        Set<String> outSeenPaths = new LinkedHashSet<>();
        appendSharedLibrariesLibPathsIfNeeded(
                aInfo.sharedLibraryInfos, aInfo, outSeenPaths, outLibPaths);

        // ApplicationInfo.sharedLibraryFiles is a public API, so anyone can change it.
        // We prepend shared libraries that the package manager hasn't seen, maintaining their
        // original order where possible.
        if (aInfo.sharedLibraryFiles != null) {
            int index = 0;
            for (String lib : sharedLibraries) {
                if (!outZipPaths.contains(lib)) {
            for (String lib : aInfo.sharedLibraryFiles) {
                if (!outSeenPaths.contains(lib) && !outZipPaths.contains(lib)) {
                    outZipPaths.add(index, lib);
                    index++;
                    appendApkLibPathIfNeeded(lib, aInfo, outLibPaths);
@@ -631,6 +659,43 @@ public final class LoadedApk {
        return mSplitLoader.getSplitPathsForSplit(splitName);
    }

    /**
     * Create a class loader for the {@code sharedLibrary}. Shared libraries are canonicalized,
     * so if we already created a class loader with that shared library, we return it.
     *
     * Implementation notes: the canonicalization of shared libraries is something dex2oat
     * also does.
     */
    ClassLoader createSharedLibraryLoader(SharedLibraryInfo sharedLibrary,
            boolean isBundledApp, String librarySearchPath, String libraryPermittedPath) {
        List<String> paths = sharedLibrary.getAllCodePaths();
        List<ClassLoader> sharedLibraries = createSharedLibrariesLoaders(
                sharedLibrary.getDependencies(), isBundledApp, librarySearchPath,
                libraryPermittedPath);
        final String jars = (paths.size() == 1) ? paths.get(0) :
                TextUtils.join(File.pathSeparator, paths);

        // Shared libraries get a null parent: this has the side effect of having canonicalized
        // shared libraries using ApplicationLoaders cache, which is the behavior we want.
        return ApplicationLoaders.getDefault().getClassLoaderWithSharedLibraries(jars,
                    mApplicationInfo.targetSdkVersion, isBundledApp, librarySearchPath,
                    libraryPermittedPath, /* parent */ null,
                    /* classLoaderName */ null, sharedLibraries);
    }

    private List<ClassLoader> createSharedLibrariesLoaders(List<SharedLibraryInfo> sharedLibraries,
            boolean isBundledApp, String librarySearchPath, String libraryPermittedPath) {
        if (sharedLibraries == null) {
            return null;
        }
        List<ClassLoader> loaders = new ArrayList<>();
        for (SharedLibraryInfo info : sharedLibraries) {
            loaders.add(createSharedLibraryLoader(
                    info, isBundledApp, librarySearchPath, libraryPermittedPath));
        }
        return loaders;
    }

    private void createOrUpdateClassLoaderLocked(List<String> addedPaths) {
        if (mPackageName.equals("android")) {
            // Note: This branch is taken for system server and we don't need to setup
@@ -759,10 +824,14 @@ public final class LoadedApk {
            // as this is early and necessary.
            StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();

            mDefaultClassLoader = ApplicationLoaders.getDefault().getClassLoader(zip,
                    mApplicationInfo.targetSdkVersion, isBundledApp, librarySearchPath,
            List<ClassLoader> sharedLibraries = createSharedLibrariesLoaders(
                    mApplicationInfo.sharedLibraryInfos, isBundledApp, librarySearchPath,
                    libraryPermittedPath);

            mDefaultClassLoader = ApplicationLoaders.getDefault().getClassLoaderWithSharedLibraries(
                    zip, mApplicationInfo.targetSdkVersion, isBundledApp, librarySearchPath,
                    libraryPermittedPath, mBaseClassLoader,
                    mApplicationInfo.classLoaderName);
                    mApplicationInfo.classLoaderName, sharedLibraries);
            mAppComponentFactory = createAppFactory(mApplicationInfo, mDefaultClassLoader);

            StrictMode.setThreadPolicy(oldPolicy);
+15 −1
Original line number Diff line number Diff line
@@ -45,6 +45,7 @@ import java.lang.annotation.RetentionPolicy;
import java.text.Collator;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.Objects;
import java.util.UUID;

@@ -815,6 +816,16 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
     */
    public String[] sharedLibraryFiles;

    /**
     * List of all shared libraries this application is linked against.  This
     * field is only set if the {@link PackageManager#GET_SHARED_LIBRARY_FILES
     * PackageManager.GET_SHARED_LIBRARY_FILES} flag was used when retrieving
     * the structure.
     *
     * {@hide}
     */
    public List<SharedLibraryInfo> sharedLibraryInfos;

    /**
     * Full path to the default directory assigned to the package for its
     * persistent data.
@@ -1458,6 +1469,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
        seInfo = orig.seInfo;
        seInfoUser = orig.seInfoUser;
        sharedLibraryFiles = orig.sharedLibraryFiles;
        sharedLibraryInfos = orig.sharedLibraryInfos;
        dataDir = orig.dataDir;
        deviceProtectedDataDir = orig.deviceProtectedDataDir;
        credentialProtectedDataDir = orig.credentialProtectedDataDir;
@@ -1533,6 +1545,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
        dest.writeString(seInfo);
        dest.writeString(seInfoUser);
        dest.writeStringArray(sharedLibraryFiles);
        dest.writeTypedList(sharedLibraryInfos);
        dest.writeString(dataDir);
        dest.writeString(deviceProtectedDataDir);
        dest.writeString(credentialProtectedDataDir);
@@ -1605,6 +1618,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
        seInfo = source.readString();
        seInfoUser = source.readString();
        sharedLibraryFiles = source.readStringArray();
        sharedLibraryInfos = source.createTypedArrayList(SharedLibraryInfo.CREATOR);
        dataDir = source.readString();
        deviceProtectedDataDir = source.readString();
        credentialProtectedDataDir = source.readString();
+1 −0
Original line number Diff line number Diff line
@@ -7555,6 +7555,7 @@ public class PackageParser {
        }
        if ((flags & PackageManager.GET_SHARED_LIBRARY_FILES) != 0) {
            ai.sharedLibraryFiles = p.usesLibraryFiles;
            ai.sharedLibraryInfos = p.usesLibraryInfos;
        }
        if (state.stopped) {
            ai.flags |= ApplicationInfo.FLAG_STOPPED;
+28 −2
Original line number Diff line number Diff line
@@ -74,6 +74,7 @@ public final class SharedLibraryInfo implements Parcelable {
    private final String mPath;
    private final String mPackageName;
    private final String mName;
    private final List<String> mCodePaths;

    private final long mVersion;
    private final @Type int mType;
@@ -84,6 +85,8 @@ public final class SharedLibraryInfo implements Parcelable {
    /**
     * Creates a new instance.
     *
     * @param codePaths For a non {@link #TYPE_BUILTIN builtin} library, the locations of jars of
     *                  this shared library. Null for builtin library.
     * @param name The lib name.
     * @param version The lib version if not builtin.
     * @param type The lib type.
@@ -92,11 +95,13 @@ public final class SharedLibraryInfo implements Parcelable {
     *
     * @hide
     */
    public SharedLibraryInfo(String path, String packageName, String name, long version, int type,
    public SharedLibraryInfo(String path, String packageName, List<String> codePaths,
            String name, long version, int type,
            VersionedPackage declaringPackage, List<VersionedPackage> dependentPackages,
            List<SharedLibraryInfo> dependencies) {
        mPath = path;
        mPackageName = packageName;
        mCodePaths = codePaths;
        mName = name;
        mVersion = version;
        mType = type;
@@ -106,7 +111,8 @@ public final class SharedLibraryInfo implements Parcelable {
    }

    private SharedLibraryInfo(Parcel parcel) {
        this(parcel.readString(), parcel.readString(), parcel.readString(), parcel.readLong(),
        this(parcel.readString(), parcel.readString(), parcel.readArrayList(null),
                parcel.readString(), parcel.readLong(),
                parcel.readInt(), parcel.readParcelable(null), parcel.readArrayList(null),
                parcel.createTypedArrayList(SharedLibraryInfo.CREATOR));
    }
@@ -154,6 +160,25 @@ public final class SharedLibraryInfo implements Parcelable {
        return mPackageName;
    }

    /**
     * Get all code paths for that library.
     *
     * @return All code paths.
     *
     * @hide
     */
    public List<String> getAllCodePaths() {
        if (getPath() != null) {
            // Builtin library.
            ArrayList<String> list = new ArrayList<>();
            list.add(getPath());
            return list;
        } else {
            // Static or dynamic library.
            return mCodePaths;
        }
    }

    /**
     * Add a library dependency to that library. Note that this
     * should be called under the package manager lock.
@@ -273,6 +298,7 @@ public final class SharedLibraryInfo implements Parcelable {
    public void writeToParcel(Parcel parcel, int flags) {
        parcel.writeString(mPath);
        parcel.writeString(mPackageName);
        parcel.writeList(mCodePaths);
        parcel.writeString(mName);
        parcel.writeLong(mVersion);
        parcel.writeInt(mType);
Loading