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

Commit c64eef62 authored by Nicolas Geoffray's avatar Nicolas Geoffray Committed by android-build-merger
Browse files

Merge "Start using shared libraries class loader." am: e7753e08

am: 4879460f

Change-Id: I0d3898a78d116aebb425a9a1cacb5dbac82b3e6d
parents 74c52585 4879460f
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