Loading core/java/android/app/ActivityThread.java +11 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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. Loading core/java/android/app/DexLoadReporter.java 0 → 100644 +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"); } } core/java/android/app/LoadedApk.java +4 −34 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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); } /** Loading core/java/android/os/FileUtils.java +3 −4 Original line number Diff line number Diff line Loading @@ -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 += "/"; } Loading services/core/java/com/android/server/pm/BackgroundDexOptService.java +2 −4 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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 Loading
core/java/android/app/ActivityThread.java +11 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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. Loading
core/java/android/app/DexLoadReporter.java 0 → 100644 +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"); } }
core/java/android/app/LoadedApk.java +4 −34 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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); } /** Loading
core/java/android/os/FileUtils.java +3 −4 Original line number Diff line number Diff line Loading @@ -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 += "/"; } Loading
services/core/java/com/android/server/pm/BackgroundDexOptService.java +2 −4 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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