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

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

Merge changes from topic 'dex' am: f665781c

am: 8a4afd3d

Change-Id: Ieb7d998721404040c0d2be010896a5dd15a3458c
parents 2b38993b 8a4afd3d
Loading
Loading
Loading
Loading
+11 −0
Original line number Diff line number Diff line
@@ -144,6 +144,7 @@ import libcore.io.DropBox;
import libcore.io.EventLogger;
import libcore.io.IoUtils;
import libcore.net.event.NetworkEventDispatcher;
import dalvik.system.BaseDexClassLoader;
import dalvik.system.CloseGuard;
import dalvik.system.VMDebug;
import dalvik.system.VMRuntime;
@@ -5348,6 +5349,16 @@ public final class ActivityThread {
            }
        }

        // If we use profiles, setup the dex reporter to notify package manager
        // of any relevant dex loads. The idle maintenance job will use the information
        // reported to optimize the loaded dex files.
        // Note that we only need one global reporter per app.
        // Make sure we do this before calling onCreate so that we can capture the
        // complete application startup.
        if (SystemProperties.getBoolean("dalvik.vm.usejitprofiles", false)) {
            BaseDexClassLoader.setReporter(DexLoadReporter.getInstance());
        }

        // Install the Network Security Config Provider. This must happen before the application
        // code is loaded to prevent issues with instances of TLS objects being created before
        // the provider is installed.
+168 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2017 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.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.app;

import android.os.FileUtils;
import android.os.RemoteException;
import android.os.SystemProperties;
import android.util.Slog;

import com.android.internal.annotations.GuardedBy;

import dalvik.system.BaseDexClassLoader;
import dalvik.system.VMRuntime;

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

/**
 * A dex load reporter which will notify package manager of any dex file loaded
 * with {@code BaseDexClassLoader}.
 * The goals are:
 *     1) discover secondary dex files so that they can be optimized during the
 *        idle maintenance job.
 *     2) determine whether or not a dex file is used by an app which does not
 *        own it (in order to select the optimal compilation method).
 * @hide
 */
/*package*/ class DexLoadReporter implements BaseDexClassLoader.Reporter {
    private static final String TAG = "DexLoadReporter";

    private static final DexLoadReporter INSTANCE = new DexLoadReporter();

    private static final boolean DEBUG = false;

    // We must guard the access to the list of data directories because
    // we might have concurrent accesses. Apps might load dex files while
    // new data dirs are registered (due to creation of LoadedApks via
    // create createApplicationContext).
    @GuardedBy("mDataDirs")
    private final Set<String> mDataDirs;

    private DexLoadReporter() {
        mDataDirs = new HashSet<>();
    }

    /*package*/ static DexLoadReporter getInstance() {
        return INSTANCE;
    }

    /**
     * Register an application data directory with the reporter.
     * The data directories are used to determine if a dex file is secondary dex or not.
     * Note that this method may be called multiple times for the same app, registering
     * different data directories. This may happen when apps share the same user id
     * ({@code android:sharedUserId}). For example, if app1 and app2 share the same user
     * id, and app1 loads app2 apk, then both data directories will be registered.
     */
    /*package*/ void registerAppDataDir(String packageName, String dataDir) {
        if (DEBUG) {
            Slog.i(TAG, "Package " + packageName + " registering data dir: " + dataDir);
        }
        // TODO(calin): A few code paths imply that the data dir
        // might be null. Investigate when that can happen.
        if (dataDir != null) {
            synchronized (mDataDirs) {
                mDataDirs.add(dataDir);
            }
        }
    }

    @Override
    public void report(List<String> dexPaths) {
        if (dexPaths.isEmpty()) {
            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);
    }

    private void notifyPackageManager(List<String> dexPaths) {
        String packageName = ActivityThread.currentPackageName();
        try {
            ActivityThread.getPackageManager().notifyDexLoad(
                    packageName, dexPaths, 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) {
        if (!SystemProperties.getBoolean("dalvik.vm.dexopt.secondary", false)) {
            return;
        }
        // Make a copy of the current data directories so that we don't keep the lock
        // while registering for profiling. The registration will perform I/O to
        // check for or create the profile.
        String[] dataDirs;
        synchronized (mDataDirs) {
            dataDirs = mDataDirs.toArray(new String[0]);
        }
        for (String dexPath : dexPaths) {
            registerSecondaryDexForProfiling(dexPath, dataDirs);
        }
    }

    private void registerSecondaryDexForProfiling(String dexPath, String[] dataDirs) {
        if (!isSecondaryDexFile(dexPath, dataDirs)) {
            // The dex path is not a secondary dex file. Nothing to do.
            return;
        }
        File secondaryProfile = getSecondaryProfileFile(dexPath);
        try {
            // Create the profile if not already there.
            // Returns true if the file was created, false if the file already exists.
            // or throws exceptions in case of errors.
            boolean created = secondaryProfile.createNewFile();
            if (DEBUG && created) {
                Slog.i(TAG, "Created profile for secondary dex: " + secondaryProfile);
            }
        } catch (IOException ex) {
            Slog.e(TAG, "Failed to create profile for secondary dex " + secondaryProfile +
                    ":" + ex.getMessage());
            // Don't move forward with the registration if we failed to create the profile.
            return;
        }

        VMRuntime.registerAppInfo(secondaryProfile.getPath(), new String[] { dexPath });
    }

    // A dex file is a secondary dex file if it is in any of the registered app
    // data directories.
    private boolean isSecondaryDexFile(String dexPath, String[] dataDirs) {
        for (String dataDir : dataDirs) {
            if (FileUtils.contains(dataDir, dexPath)) {
                return true;
            }
        }
        return false;
    }

    // Secondary dex profiles are stored next to the dex file and have the same
    // name with '.prof' appended.
    // NOTE: Keep in sync with installd.
    private File getSecondaryProfileFile(String dexPath) {
        return new File(dexPath + ".prof");
    }
}
+4 −34
Original line number Diff line number Diff line
@@ -51,7 +51,6 @@ import android.util.SparseArray;
import android.view.Display;
import android.view.DisplayAdjustments;

import dalvik.system.BaseDexClassLoader;
import dalvik.system.VMRuntime;

import java.io.File;
@@ -610,39 +609,10 @@ public final class LoadedApk {
        VMRuntime.registerAppInfo(profileFile.getPath(),
                codePaths.toArray(new String[codePaths.size()]));

        // Setup the reporter to notify package manager of any relevant dex loads.
        // At this point the primary apk is loaded and will not be reported.
        // Anything loaded from now on will be tracked as a potential secondary
        // or foreign dex file. The goal is to enable:
        //    1) monitoring and compilation of secondary dex file
        //    2) track whether or not a dex file is used by other apps (used to
        //       determined the compilation filter of apks).
        if (BaseDexClassLoader.getReporter() != DexLoadReporter.INSTANCE) {
            // Set the dex load reporter if not already set.
            // Note that during the app's life cycle different LoadedApks may be
            // created and loaded (e.g. if two different apps share the same runtime).
            BaseDexClassLoader.setReporter(DexLoadReporter.INSTANCE);
        }
    }

    private static class DexLoadReporter implements BaseDexClassLoader.Reporter {
        private static final DexLoadReporter INSTANCE = new DexLoadReporter();

        private DexLoadReporter() {}

        @Override
        public void report(List<String> dexPaths) {
            if (dexPaths.isEmpty()) {
                return;
            }
            String packageName = ActivityThread.currentPackageName();
            try {
                ActivityThread.getPackageManager().notifyDexLoad(
                        packageName, dexPaths, VMRuntime.getRuntime().vmInstructionSet());
            } catch (RemoteException re) {
                Slog.e(TAG, "Failed to notify PM about dex load for package " + packageName, re);
            }
        }
        // Register the app data directory with the reporter. It will
        // help deciding whether or not a dex file is the primary apk or a
        // secondary dex.
        DexLoadReporter.getInstance().registerAppDataDir(mPackageName, mDataDir);
    }

    /**
+3 −4
Original line number Diff line number Diff line
@@ -428,14 +428,13 @@ public class FileUtils {
     */
    public static boolean contains(File dir, File file) {
        if (dir == null || file == null) return false;
        return contains(dir.getAbsolutePath(), file.getAbsolutePath());
    }

        String dirPath = dir.getAbsolutePath();
        String filePath = file.getAbsolutePath();

    public static boolean contains(String dirPath, String filePath) {
        if (dirPath.equals(filePath)) {
            return true;
        }

        if (!dirPath.endsWith("/")) {
            dirPath += "/";
        }
+2 −4
Original line number Diff line number Diff line
@@ -49,8 +49,6 @@ public class BackgroundDexOptService extends JobService {

    private static final boolean DEBUG = false;

    private static final long RETRY_LATENCY = 4 * AlarmManager.INTERVAL_HOUR;

    private static final int JOB_IDLE_OPTIMIZE = 800;
    private static final int JOB_POST_BOOT_UPDATE = 801;

@@ -292,8 +290,8 @@ public class BackgroundDexOptService extends JobService {
                            PackageManagerService.REASON_BACKGROUND_DEXOPT,
                            /* force */ false)
                    : pm.performDexOptSecondary(pkg,
                            PackageManagerServiceCompilerMapping.getFullCompilerFilter(),
                            /* force */ true);
                            PackageManagerService.REASON_BACKGROUND_DEXOPT,
                            /* force */ false);
            if (success) {
                // Dexopt succeeded, remove package from the list of failing ones.
                synchronized (failedPackageNames) {
Loading