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

Commit 371fcb7c authored by Nicolas Geoffray's avatar Nicolas Geoffray
Browse files

Revert "[DexLoadReporter] Report classloader contexts directly f..."

Revert "Fix shared libraries not being reported via Reporter"

Revert submission 1198456-slclc

Reason for revert: Fails on luci:
https://ci.chromium.org/p/art/builders/ci/host-x86_64-cdex-fast/3123

Exempt-From-Owner-Approval: pure revert

Bug: 148494302
Reverted Changes:
I46d8d9105: Fix shared libraries not being reported via Report...
I00357cfe0: [DexLoadReporter] Report classloader contexts dire...

Change-Id: Ib58066e8f059642a11d9eaab02ec0b8b3217e487
parent a05766e5
Loading
Loading
Loading
Loading
+29 −10
Original line number Diff line number Diff line
@@ -28,8 +28,9 @@ import dalvik.system.VMRuntime;

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

/**
@@ -86,32 +87,50 @@ import java.util.Set;
    }

    @Override
    public void report(Map<String, String> classLoaderContextMap) {
        if (classLoaderContextMap.isEmpty()) {
            Slog.wtf(TAG, "Bad call to DexLoadReporter: empty classLoaderContextMap");
    public void report(List<ClassLoader> 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(classLoaderContextMap);
        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(classLoaderContextMap.keySet());
        registerSecondaryDexForProfiling(dexPathsForRegistration);
    }

    private void notifyPackageManager(Map<String, String> classLoaderContextMap) {
    private void notifyPackageManager(List<ClassLoader> classLoadersChain,
            List<String> classPaths) {
        // Get the class loader names for the binder call.
        List<String> classLoadersNames = new ArrayList<>(classPaths.size());
        for (ClassLoader classLoader : classLoadersChain) {
            classLoadersNames.add(classLoader.getClass().getName());
        }
        String packageName = ActivityThread.currentPackageName();
        try {
            ActivityThread.getPackageManager().notifyDexLoad(packageName,
                    classLoaderContextMap, VMRuntime.getRuntime().vmInstructionSet());
            ActivityThread.getPackageManager().notifyDexLoad(
                    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(Set<String> dexPaths) {
    private void registerSecondaryDexForProfiling(String[] dexPaths) {
        if (!SystemProperties.getBoolean("dalvik.vm.dexopt.secondary", false)) {
            return;
        }
+11 −4
Original line number Diff line number Diff line
@@ -529,12 +529,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 classLoaderContextMap a map from file paths to dex files that have been loaded to
     *     the class loader context that was used to load them.
     * @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}, or null if the class loader's classpath is not known.
     *     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 Map<String, String> classLoaderContextMap, 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.
+3 −3
Original line number Diff line number Diff line
@@ -9764,8 +9764,8 @@ public class PackageManagerService extends IPackageManager.Stub
    }
    @Override
    public void notifyDexLoad(String loadingPackageName, Map<String, String> classLoaderContextMap,
            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) {
@@ -9773,7 +9773,7 @@ public class PackageManagerService extends IPackageManager.Stub
                + loadingPackageName + ", user=" + userId);
            return;
        }
        mDexManager.notifyDexLoad(ai, classLoaderContextMap, loaderIsa, userId);
        mDexManager.notifyDexLoad(ai, classLoaderNames, classPaths, loaderIsa, userId);
    }
    @Override
+47 −17
Original line number Diff line number Diff line
@@ -44,8 +44,6 @@ import com.android.server.pm.PackageDexOptimizer;
import com.android.server.pm.PackageManagerService;
import com.android.server.pm.PackageManagerServiceUtils;

import dalvik.system.VMRuntime;

import java.io.File;
import java.io.IOException;
import java.util.Arrays;
@@ -145,15 +143,22 @@ public class DexManager {
     * return as fast as possible.
     *
     * @param loadingAppInfo the package performing the load
     * @param classLoaderContextMap a map from file paths to dex files that have been loaded to
     *     the class loader context that was used to load them.
     * @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}, or null if the class loader's classpath is not known.
     *     The dex files found in the first class path will be recorded in the usage file.
     * @param loaderIsa the ISA of the app loading the dex files
     * @param loaderUserId the user id which runs the code loading the dex files
     */
    public void notifyDexLoad(ApplicationInfo loadingAppInfo,
            Map<String, String> classLoaderContextMap, String loaderIsa, int loaderUserId) {
    public void notifyDexLoad(ApplicationInfo loadingAppInfo, List<String> classLoadersNames,
            List<String> classPaths, String loaderIsa, int loaderUserId) {
        try {
            notifyDexLoadInternal(loadingAppInfo, classLoaderContextMap, loaderIsa,
            notifyDexLoadInternal(loadingAppInfo, classLoadersNames, classPaths, loaderIsa,
                    loaderUserId);
        } catch (Exception e) {
            Slog.w(TAG, "Exception while notifying dex load for package " +
@@ -163,23 +168,46 @@ public class DexManager {

    @VisibleForTesting
    /*package*/ void notifyDexLoadInternal(ApplicationInfo loadingAppInfo,
            Map<String, String> classLoaderContextMap, String loaderIsa,
            List<String> classLoaderNames, List<String> classPaths, String loaderIsa,
            int loaderUserId) {
        if (classLoaderContextMap == null) {
        if (classLoaderNames.size() != classPaths.size()) {
            Slog.wtf(TAG, "Bad call to noitfyDexLoad: args have different size");
            return;
        }
        if (classLoaderContextMap.isEmpty()) {
        if (classLoaderNames.isEmpty()) {
            Slog.wtf(TAG, "Bad call to notifyDexLoad: class loaders list is empty");
            return;
        }
        if (!PackageManagerServiceUtils.checkISA(loaderIsa)) {
            Slog.w(TAG, "Loading dex files " + classLoaderContextMap.keySet()
                    + " in unsupported ISA: " + loaderIsa + "?");
            Slog.w(TAG, "Loading dex files " + classPaths + " in unsupported ISA: " +
                    loaderIsa + "?");
            return;
        }

        for (Map.Entry<String, String> mapping : classLoaderContextMap.entrySet()) {
            String dexPath = mapping.getKey();
        // The first classpath should never be null because the first classloader
        // should always be an instance of BaseDexClassLoader.
        String firstClassPath = classPaths.get(0);
        if (firstClassPath == null) {
            return;
        }
        // The classpath is represented as a list of dex files separated by File.pathSeparator.
        String[] dexPathsToRegister = firstClassPath.split(File.pathSeparator);

        // Encode the class loader contexts for the dexPathsToRegister.
        String[] classLoaderContexts = DexoptUtils.processContextForDexLoad(
                classLoaderNames, classPaths);

        // A null classLoaderContexts means that there are unsupported class loaders in the
        // chain.
        if (classLoaderContexts == null) {
            if (DEBUG) {
                Slog.i(TAG, loadingAppInfo.packageName +
                        " uses unsupported class loader in " + classLoaderNames);
            }
        }

        int dexPathIndex = 0;
        for (String dexPath : dexPathsToRegister) {
            // Find the owning package name.
            DexSearchResult searchResult = getDexPackage(loadingAppInfo, dexPath, loaderUserId);

@@ -201,6 +229,7 @@ public class DexManager {
                    // If the dex file is the primary apk (or a split) and not isUsedByOtherApps
                    // do not record it. This case does not bring any new usable information
                    // and can be safely skipped.
                    dexPathIndex++;
                    continue;
                }

@@ -210,13 +239,13 @@ public class DexManager {
                            searchResult.mOwningPackageName, loadingAppInfo.packageName);
                }

                String classLoaderContext = mapping.getValue();
                if (classLoaderContext != null
                        && VMRuntime.isValidClassLoaderContext(classLoaderContext)) {
                if (classLoaderContexts != null) {

                    // Record dex file usage. If the current usage is a new pattern (e.g. new
                    // secondary, or UsedByOtherApps), record will return true and we trigger an
                    // async write to disk to make sure we don't loose the data in case of a reboot.

                    String classLoaderContext = classLoaderContexts[dexPathIndex];
                    if (mPackageDexUsage.record(searchResult.mOwningPackageName,
                            dexPath, loaderUserId, loaderIsa, isUsedByOtherApps, primaryOrSplit,
                            loadingAppInfo.packageName, classLoaderContext)) {
@@ -230,6 +259,7 @@ public class DexManager {
                    Slog.i(TAG, "Could not find owning package for dex file: " + dexPath);
                }
            }
            dexPathIndex++;
        }
    }

+5 −17
Original line number Diff line number Diff line
@@ -83,9 +83,8 @@ public class PackageDexUsage extends AbstractStatsBase<Void> {
            "=UnknownClassLoaderContext=";

    // The marker used for unsupported class loader contexts (no longer written, may occur in old
    // files so discarded on read). Note: this matches
    // ClassLoaderContext::kUnsupportedClassLoaderContextEncoding in the runtime.
    /*package*/ static final String UNSUPPORTED_CLASS_LOADER_CONTEXT =
    // files so discarded on read).
    private static final String UNSUPPORTED_CLASS_LOADER_CONTEXT =
            "=UnsupportedClassLoaderContext=";

    /**
@@ -134,9 +133,6 @@ public class PackageDexUsage extends AbstractStatsBase<Void> {
        if (classLoaderContext == null) {
            throw new IllegalArgumentException("Null classLoaderContext");
        }
        if (classLoaderContext.equals(UNSUPPORTED_CLASS_LOADER_CONTEXT)) {
            return false;
        }

        synchronized (mPackageUseInfoMap) {
            PackageUseInfo packageUseInfo = mPackageUseInfoMap.get(owningPackageName);
@@ -847,11 +843,10 @@ public class PackageDexUsage extends AbstractStatsBase<Void> {
            boolean updateLoadingPackages = mLoadingPackages.addAll(dexUseInfo.mLoadingPackages);

            String oldClassLoaderContext = mClassLoaderContext;
            if (isUnknownOrUnsupportedContext(mClassLoaderContext)) {
            if (UNKNOWN_CLASS_LOADER_CONTEXT.equals(mClassLoaderContext)) {
                // Can happen if we read a previous version.
                mClassLoaderContext = dexUseInfo.mClassLoaderContext;
            } else if (!isUnknownOrUnsupportedContext(dexUseInfo.mClassLoaderContext)
                        && !Objects.equals(mClassLoaderContext, dexUseInfo.mClassLoaderContext)) {
            } else if (!Objects.equals(mClassLoaderContext, dexUseInfo.mClassLoaderContext)) {
                // We detected a context change.
                mClassLoaderContext = VARIABLE_CLASS_LOADER_CONTEXT;
            }
@@ -862,13 +857,6 @@ public class PackageDexUsage extends AbstractStatsBase<Void> {
                    || !Objects.equals(oldClassLoaderContext, mClassLoaderContext);
        }

        private static boolean isUnknownOrUnsupportedContext(String context) {
            // TODO: Merge UNKNOWN_CLASS_LOADER_CONTEXT & UNSUPPORTED_CLASS_LOADER_CONTEXT cases
            // into UNSUPPORTED_CLASS_LOADER_CONTEXT.
            return UNKNOWN_CLASS_LOADER_CONTEXT.equals(context)
                    || UNSUPPORTED_CLASS_LOADER_CONTEXT.equals(context);
        }

        public boolean isUsedByOtherApps() {
            return mIsUsedByOtherApps;
        }
@@ -890,7 +878,7 @@ public class PackageDexUsage extends AbstractStatsBase<Void> {
        public boolean isUnknownClassLoaderContext() {
            // The class loader context may be unknown if we loaded the data from a previous version
            // which didn't save the context.
            return isUnknownOrUnsupportedContext(mClassLoaderContext);
            return UNKNOWN_CLASS_LOADER_CONTEXT.equals(mClassLoaderContext);
        }

        public boolean isVariableClassLoaderContext() {
Loading