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

Commit 2053168e authored by Narayan Kamath's avatar Narayan Kamath
Browse files

Dexopt for Context.createPackageContext when code is included.

The package manager now keeps track of per ISA dex-opt state.

There are two important things to keep in mind here :

- dexopt can potentially be very slow. In cases where the target
  package hasn't been dexopted yet, this can take multiple seconds
  and may cause an ANR in the caller if the context is being
  created from the main thread.
- We will need to remove the constraint that dexopt can only be
  requested by the system (or root). Apps will implicitly be
  requesting dexopt by asking for package contexts with code included.
  It's important to note that unlike dalvik, the dexopt stage in ART
  isn't optional. ART cannot load classes directly from dex files.

bug: 15313272
Change-Id: I0bd6c323a9c1f62f1c08f6292b7f0f7f08942726
parent 93a412ea
Loading
Loading
Loading
Loading
+17 −0
Original line number Diff line number Diff line
@@ -56,6 +56,7 @@ import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.Objects;

final class IntentReceiverLeaked extends AndroidRuntimeException {
    public IntentReceiverLeaked(String msg) {
@@ -252,6 +253,22 @@ public final class LoadedApk {
            }

            if (mIncludeCode && !mPackageName.equals("android")) {
                // Avoid the binder call when the package is the current application package.
                // The activity manager will perform ensure that dexopt is performed before
                // spinning up the process.
                if (!Objects.equals(mPackageName, ActivityThread.currentPackageName())) {
                    final String isa = VMRuntime.getRuntime().vmInstructionSet();
                    try {
                        // TODO: We can probably do away with the isa argument since
                        // the AM and PM have enough information to figure this out
                        // themselves. If we do need it, we should match it against the
                        // list of devices ISAs before sending it down to installd.
                        ActivityThread.getPackageManager().performDexOptIfNeeded(mPackageName, isa);
                    } catch (RemoteException re) {
                        // Ignored.
                    }
                }

                final ArrayList<String> zipPaths = new ArrayList<>();
                final ArrayList<String> libPaths = new ArrayList<>();

+9 −3
Original line number Diff line number Diff line
@@ -384,10 +384,16 @@ interface IPackageManager {

    /**
     * Ask the package manager to perform dex-opt (if needed) on the given
     * package, if it already hasn't done mode.  Only does this if running
     * in the special development "no pre-dexopt" mode.
     * package and for the given instruction set if it already hasn't done
     * so.
     *
     * If the supplied instructionSet is null, the package manager will use
     * the packages default instruction set.
     *
     * In most cases, apps are dexopted in advance and this function will
     * be a no-op.
     */
    boolean performDexOpt(String packageName);
    boolean performDexOptIfNeeded(String packageName, String instructionSet);

    /**
     * Update status of external media on the package manager to scan and
+1 −1
Original line number Diff line number Diff line
@@ -4201,7 +4201,7 @@ public class PackageParser {
        public int mPreferredOrder = 0;

        // For use by package manager to keep track of where it needs to do dexopt.
        public boolean mDexOptNeeded = true;
        public final ArraySet<String> mDexOptPerformed = new ArraySet<>(4);

        // For use by package manager to keep track of when a package was last used.
        public long mLastPackageUsageTimeInMills;
+1 −1
Original line number Diff line number Diff line
@@ -2809,7 +2809,7 @@ public final class ActivityManagerService extends ActivityManagerNative
    void ensurePackageDexOpt(String packageName) {
        IPackageManager pm = AppGlobals.getPackageManager();
        try {
            if (pm.performDexOpt(packageName)) {
            if (pm.performDexOptIfNeeded(packageName, null /* instruction set */)) {
                mDidDexOpt = true;
            }
        } catch (RemoteException e) {
+1 −1
Original line number Diff line number Diff line
@@ -75,7 +75,7 @@ public class BackgroundDexOptService extends JobService {
                        schedule(BackgroundDexOptService.this);
                        return;
                    }
                    pm.performDexOpt(pkg, false);
                    pm.performDexOpt(pkg, null /* instruction set */, false);
                }
                // ran to completion, so we abandon our timeslice and do not reschedule
                jobFinished(jobParams, false);
Loading