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

Commit e93209ba authored by Calin Juravle's avatar Calin Juravle Committed by android-build-merger
Browse files

Merge changes from topic 'class-loaders-mr1' into oc-mr1-dev

am: 565cab11

Change-Id: I11f2a6d1df31d1a27ce5295bcdf6fbbd540060bc
parents 533c77b4 565cab11
Loading
Loading
Loading
Loading
+31 −9
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@ import dalvik.system.VMRuntime;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@@ -86,29 +87,50 @@ import java.util.Set;
    }

    @Override
    public void report(List<String> dexPaths) {
        if (dexPaths.isEmpty()) {
    public void report(List<BaseDexClassLoader> classLoadersChain, List<String> classPaths) {
        if (classLoadersChain.size() != classPaths.size()) {
            Slog.wtf(TAG, "Bad call to DexLoadReporter: argument size mismatch");
            return;
        }
        if (classPaths.isEmpty()) {
            Slog.wtf(TAG, "Bad call to DexLoadReporter: empty dex paths");
            return;
        }

        // The first element of classPaths is the list of dex files that should be registered.
        // The classpath is represented as a list of dex files separated by File.pathSeparator.
        String[] dexPathsForRegistration = classPaths.get(0).split(File.pathSeparator);
        if (dexPathsForRegistration.length == 0) {
            // No dex files to register.
            return;
        }

        // Notify the package manager about the dex loads unconditionally.
        // The load might be for either a primary or secondary dex file.
        notifyPackageManager(dexPaths);
        // Check for secondary dex files and register them for profiling if
        // possible.
        registerSecondaryDexForProfiling(dexPaths);
        notifyPackageManager(classLoadersChain, classPaths);
        // Check for secondary dex files and register them for profiling if possible.
        // Note that we only register the dex paths belonging to the first class loader.
        registerSecondaryDexForProfiling(dexPathsForRegistration);
    }

    private void notifyPackageManager(List<String> dexPaths) {
    private void notifyPackageManager(List<BaseDexClassLoader> classLoadersChain,
            List<String> classPaths) {
        // Get the class loader names for the binder call.
        List<String> classLoadersNames = new ArrayList<>(classPaths.size());
        for (BaseDexClassLoader bdc : classLoadersChain) {
            classLoadersNames.add(bdc.getClass().getName());
        }
        String packageName = ActivityThread.currentPackageName();
        try {
            ActivityThread.getPackageManager().notifyDexLoad(
                    packageName, dexPaths, VMRuntime.getRuntime().vmInstructionSet());
                    packageName, classLoadersNames, classPaths,
                    VMRuntime.getRuntime().vmInstructionSet());
        } catch (RemoteException re) {
            Slog.e(TAG, "Failed to notify PM about dex load for package " + packageName, re);
        }
    }

    private void registerSecondaryDexForProfiling(List<String> dexPaths) {
    private void registerSecondaryDexForProfiling(String[] dexPaths) {
        if (!SystemProperties.getBoolean("dalvik.vm.dexopt.secondary", false)) {
            return;
        }
+11 −3
Original line number Diff line number Diff line
@@ -469,11 +469,19 @@ interface IPackageManager {
     * Notify the package manager that a list of dex files have been loaded.
     *
     * @param loadingPackageName the name of the package who performs the load
     * @param dexPats the list of the dex files paths that have been loaded
     * @param classLoadersNames the names of the class loaders present in the loading chain. The
     *    list encodes the class loader chain in the natural order. The first class loader has
     *    the second one as its parent and so on. The dex files present in the class path of the
     *    first class loader will be recorded in the usage file.
     * @param classPaths the class paths corresponding to the class loaders names from
     *     {@param classLoadersNames}. The the first element corresponds to the first class loader
     *     and so on. A classpath is represented as a list of dex files separated by
     *     {@code File.pathSeparator}.
     *     The dex files found in the first class path will be recorded in the usage file.
     * @param loaderIsa the ISA of the loader process
     */
    oneway void notifyDexLoad(String loadingPackageName, in List<String> dexPaths,
            String loaderIsa);
    oneway void notifyDexLoad(String loadingPackageName, in List<String> classLoadersNames,
            in List<String> classPaths, String loaderIsa);

    /**
     * Register an application dex module with the package manager.
+6 −2
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ package com.android.internal.os;
import android.os.Trace;

import dalvik.system.DelegateLastClassLoader;
import dalvik.system.DexClassLoader;
import dalvik.system.PathClassLoader;

/**
@@ -31,6 +32,7 @@ public class ClassLoaderFactory {
    private ClassLoaderFactory() {}

    private static final String PATH_CLASS_LOADER_NAME = PathClassLoader.class.getName();
    private static final String DEX_CLASS_LOADER_NAME = DexClassLoader.class.getName();
    private static final String DELEGATE_LAST_CLASS_LOADER_NAME =
            DelegateLastClassLoader.class.getName();

@@ -44,12 +46,14 @@ public class ClassLoaderFactory {
    }

    /**
     * Returns true if {@code name} is the encoding for the PathClassLoader.
     * Returns true if {@code name} is the encoding for either PathClassLoader or DexClassLoader.
     * The two class loaders are grouped together because they have the same behaviour.
     */
    public static boolean isPathClassLoaderName(String name) {
        // For null values we default to PathClassLoader. This cover the case when packages
        // don't specify any value for their class loaders.
        return name == null || PATH_CLASS_LOADER_NAME.equals(name);
        return name == null || PATH_CLASS_LOADER_NAME.equals(name) ||
                DEX_CLASS_LOADER_NAME.equals(name);
    }

    /**
+30 −12
Original line number Diff line number Diff line
@@ -33,12 +33,12 @@ import com.android.internal.util.IndentingPrintWriter;
import com.android.server.pm.Installer.InstallerException;
import com.android.server.pm.dex.DexoptOptions;
import com.android.server.pm.dex.DexoptUtils;
import com.android.server.pm.dex.PackageDexUsage;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import dalvik.system.DexFile;

@@ -251,13 +251,12 @@ public class PackageDexOptimizer {
     * throwing exceptions). Or maybe make a separate call to installd to get DexOptNeeded, though
     * that seems wasteful.
     */
    public int dexOptSecondaryDexPath(ApplicationInfo info, String path, Set<String> isas,
            String compilerFilter, boolean isUsedByOtherApps, boolean downgrade) {
    public int dexOptSecondaryDexPath(ApplicationInfo info, String path,
            PackageDexUsage.DexUseInfo dexUseInfo, DexoptOptions options) {
        synchronized (mInstallLock) {
            final long acquireTime = acquireWakeLockLI(info.uid);
            try {
                return dexOptSecondaryDexPathLI(info, path, isas, compilerFilter,
                        isUsedByOtherApps, downgrade);
                return dexOptSecondaryDexPathLI(info, path, dexUseInfo, options);
            } finally {
                releaseWakeLockLI(acquireTime);
            }
@@ -298,9 +297,16 @@ public class PackageDexOptimizer {
    }

    @GuardedBy("mInstallLock")
    private int dexOptSecondaryDexPathLI(ApplicationInfo info, String path, Set<String> isas,
            String compilerFilter, boolean isUsedByOtherApps, boolean downgrade) {
        compilerFilter = getRealCompilerFilter(info, compilerFilter, isUsedByOtherApps);
    private int dexOptSecondaryDexPathLI(ApplicationInfo info, String path,
            PackageDexUsage.DexUseInfo dexUseInfo, DexoptOptions options) {
        if (options.isDexoptOnlySharedDex() && !dexUseInfo.isUsedByOtherApps()) {
            // We are asked to optimize only the dex files used by other apps and this is not
            // on of them: skip it.
            return DEX_OPT_SKIPPED;
        }

        String compilerFilter = getRealCompilerFilter(info, options.getCompilerFilter(),
                dexUseInfo.isUsedByOtherApps());
        // Get the dexopt flags after getRealCompilerFilter to make sure we get the correct flags.
        // Secondary dex files are currently not compiled at boot.
        int dexoptFlags = getDexFlags(info, compilerFilter, /* bootComplete */ true)
@@ -317,20 +323,32 @@ public class PackageDexOptimizer {
            return DEX_OPT_FAILED;
        }
        Log.d(TAG, "Running dexopt on: " + path
                + " pkg=" + info.packageName + " isa=" + isas
                + " pkg=" + info.packageName + " isa=" + dexUseInfo.getLoaderIsas()
                + " dexoptFlags=" + printDexoptFlags(dexoptFlags)
                + " target-filter=" + compilerFilter);

        String classLoaderContext;
        if (dexUseInfo.isUnknownClassLoaderContext() ||
                dexUseInfo.isUnsupportedClassLoaderContext() ||
                dexUseInfo.isVariableClassLoaderContext()) {
            // If we have an unknown (not yet set), unsupported (custom class loaders), or a
            // variable class loader chain, compile without a context and mark the oat file with
            // SKIP_SHARED_LIBRARY_CHECK. Note that his might lead to a incorrect compilation.
            // TODO(calin): We should just extract in this case.
            classLoaderContext = SKIP_SHARED_LIBRARY_CHECK;
        } else {
            classLoaderContext = dexUseInfo.getClassLoaderContext();
        }
        try {
            for (String isa : isas) {
            for (String isa : dexUseInfo.getLoaderIsas()) {
                // Reuse the same dexopt path as for the primary apks. We don't need all the
                // arguments as some (dexopNeeded and oatDir) will be computed by installd because
                // system server cannot read untrusted app content.
                // TODO(calin): maybe add a separate call.
                mInstaller.dexopt(path, info.uid, info.packageName, isa, /*dexoptNeeded*/ 0,
                        /*oatDir*/ null, dexoptFlags,
                        compilerFilter, info.volumeUuid, SKIP_SHARED_LIBRARY_CHECK, info.seInfoUser,
                        downgrade);
                        compilerFilter, info.volumeUuid, classLoaderContext, info.seInfoUser,
                        options.isDowngrade());
            }

            return DEX_OPT_PERFORMED;
+3 −2
Original line number Diff line number Diff line
@@ -9686,7 +9686,8 @@ public class PackageManagerService extends IPackageManager.Stub
    }
    @Override
    public void notifyDexLoad(String loadingPackageName, List<String> dexPaths, String loaderIsa) {
    public void notifyDexLoad(String loadingPackageName, List<String> classLoaderNames,
            List<String> classPaths, String loaderIsa) {
        int userId = UserHandle.getCallingUserId();
        ApplicationInfo ai = getApplicationInfo(loadingPackageName, /*flags*/ 0, userId);
        if (ai == null) {
@@ -9694,7 +9695,7 @@ public class PackageManagerService extends IPackageManager.Stub
                + loadingPackageName + ", user=" + userId);
            return;
        }
        mDexManager.notifyDexLoad(ai, dexPaths, loaderIsa, userId);
        mDexManager.notifyDexLoad(ai, classLoaderNames, classPaths, loaderIsa, userId);
    }
    @Override
Loading