Merge "Register secondary dex files for JIT profiling"
This commit is contained in:
committed by
Android (Google) Code Review
commit
f18cec265d
@@ -5579,7 +5579,7 @@ public final class ActivityThread {
|
||||
// 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.INSTANCE);
|
||||
BaseDexClassLoader.setReporter(DexLoadReporter.getInstance());
|
||||
}
|
||||
|
||||
// Install the Network Security Config Provider. This must happen before the application
|
||||
|
||||
@@ -16,13 +16,21 @@
|
||||
|
||||
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
|
||||
@@ -37,15 +45,60 @@ import java.util.List;
|
||||
/*package*/ class DexLoadReporter implements BaseDexClassLoader.Reporter {
|
||||
private static final String TAG = "DexLoadReporter";
|
||||
|
||||
/*package*/ static final DexLoadReporter INSTANCE = new DexLoadReporter();
|
||||
private static final DexLoadReporter INSTANCE = new DexLoadReporter();
|
||||
|
||||
private 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(
|
||||
@@ -54,4 +107,62 @@ import java.util.List;
|
||||
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");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -750,6 +750,11 @@ public final class LoadedApk {
|
||||
|
||||
VMRuntime.registerAppInfo(profileFile.getPath(),
|
||||
codePaths.toArray(new String[codePaths.size()]));
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user