Merge changes from topic 'dex'

am: f665781c74

Change-Id: I31c202a56d8f92634cc1d5d84106e27cb8c23bfd
This commit is contained in:
Calin Juravle
2017-03-29 01:27:37 +00:00
committed by android-build-merger
10 changed files with 497 additions and 64 deletions

View File

@@ -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.

View File

@@ -0,0 +1,168 @@
/*
* 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");
}
}

View File

@@ -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);
}
/**

View File

@@ -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 += "/";
}