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

Commit f2db00fd authored by Brian Carlstrom's avatar Brian Carlstrom Committed by Android Git Automerger
Browse files

am edb88bcd: Merge "Use package usage information to decide what dex files to...

am edb88bcd: Merge "Use package usage information to decide what dex files to optimize in PackageManagerService"

* commit 'edb88bcd':
  Use package usage information to decide what dex files to optimize in PackageManagerService
parents cc6b9eb2 edb88bcd
Loading
Loading
Loading
Loading
+7 −4
Original line number Original line Diff line number Diff line
@@ -3534,8 +3534,11 @@ public class PackageParser {
        // file an app came from.
        // file an app came from.
        public String mScanPath;
        public String mScanPath;


        // For use by package manager to keep track of where it has done dexopt.
        // For use by package manager to keep track of where it needs to do dexopt.
        public boolean mDidDexOpt;
        public boolean mDexOptNeeded = true;

        // For use by package manager to keep track of when a package was last used.
        public long mLastPackageUsageTimeInMills;


        // // User set enabled state.
        // // User set enabled state.
        // public int mSetEnabled = PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
        // public int mSetEnabled = PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
+1 −1
Original line number Original line Diff line number Diff line
@@ -924,7 +924,7 @@ public final class ActivityManagerService extends ActivityManagerNative
    /**
    /**
     * This is set if we had to do a delayed dexopt of an app before launching
     * This is set if we had to do a delayed dexopt of an app before launching
     * it, to increasing the ANR timeouts in that case.
     * it, to increase the ANR timeouts in that case.
     */
     */
    boolean mDidDexOpt;
    boolean mDidDexOpt;
+267 −71
Original line number Original line Diff line number Diff line
@@ -28,10 +28,12 @@ import static android.system.OsConstants.S_IRGRP;
import static android.system.OsConstants.S_IXGRP;
import static android.system.OsConstants.S_IXGRP;
import static android.system.OsConstants.S_IROTH;
import static android.system.OsConstants.S_IROTH;
import static android.system.OsConstants.S_IXOTH;
import static android.system.OsConstants.S_IXOTH;
import static android.os.Process.PACKAGE_INFO_GID;
import static android.os.Process.SYSTEM_UID;
import static com.android.internal.util.ArrayUtils.appendInt;
import static com.android.internal.util.ArrayUtils.appendInt;
import static com.android.internal.util.ArrayUtils.removeInt;
import static com.android.internal.util.ArrayUtils.removeInt;
import android.content.pm.PackageParser.*;
import com.android.internal.R;
import com.android.internal.app.IMediaContainerService;
import com.android.internal.app.IMediaContainerService;
import com.android.internal.app.ResolverActivity;
import com.android.internal.app.ResolverActivity;
import com.android.internal.content.NativeLibraryHelper;
import com.android.internal.content.NativeLibraryHelper;
@@ -42,8 +44,8 @@ import com.android.internal.util.XmlUtils;
import com.android.server.DeviceStorageMonitorService;
import com.android.server.DeviceStorageMonitorService;
import com.android.server.EventLogTags;
import com.android.server.EventLogTags;
import com.android.server.IntentResolver;
import com.android.server.IntentResolver;
import com.android.server.Watchdog;
import com.android.server.Watchdog;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer;
import org.xmlpull.v1.XmlSerializer;
@@ -78,6 +80,7 @@ import android.content.pm.PackageCleanItem;
import android.content.pm.PackageInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageInfoLite;
import android.content.pm.PackageInfoLite;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager;
import android.content.pm.PackageParser.ActivityIntentInfo;
import android.content.pm.PackageParser;
import android.content.pm.PackageParser;
import android.content.pm.PackageStats;
import android.content.pm.PackageStats;
import android.content.pm.PackageUserState;
import android.content.pm.PackageUserState;
@@ -121,6 +124,7 @@ import android.system.ErrnoException;
import android.system.Os;
import android.system.Os;
import android.system.StructStat;
import android.system.StructStat;
import android.text.TextUtils;
import android.text.TextUtils;
import android.util.AtomicFile;
import android.util.DisplayMetrics;
import android.util.DisplayMetrics;
import android.util.EventLog;
import android.util.EventLog;
import android.util.Log;
import android.util.Log;
@@ -132,6 +136,7 @@ import android.util.Xml;
import android.view.Display;
import android.view.Display;
import android.view.WindowManager;
import android.view.WindowManager;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileDescriptor;
@@ -141,7 +146,9 @@ import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileReader;
import java.io.FilenameFilter;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.io.PrintWriter;
import java.nio.charset.StandardCharsets;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
import java.security.PublicKey;
import java.security.cert.CertificateException;
import java.security.cert.CertificateException;
@@ -158,12 +165,14 @@ import java.util.Iterator;
import java.util.List;
import java.util.List;
import java.util.Map;
import java.util.Map;
import java.util.Set;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicLong;
import dalvik.system.DexFile;
import dalvik.system.StaleDexCacheError;
import dalvik.system.VMRuntime;
import dalvik.system.VMRuntime;
import libcore.io.IoUtils;
import libcore.io.IoUtils;
import com.android.internal.R;
/**
/**
 * Keep track of all those .apks everywhere.
 * Keep track of all those .apks everywhere.
 * 
 * 
@@ -190,6 +199,7 @@ public class PackageManagerService extends IPackageManager.Stub {
    private static final boolean DEBUG_PACKAGE_SCANNING = false;
    private static final boolean DEBUG_PACKAGE_SCANNING = false;
    private static final boolean DEBUG_APP_DIR_OBSERVER = false;
    private static final boolean DEBUG_APP_DIR_OBSERVER = false;
    private static final boolean DEBUG_VERIFY = false;
    private static final boolean DEBUG_VERIFY = false;
    private static final boolean DEBUG_DEXOPT = false;
    private static final int RADIO_UID = Process.PHONE_UID;
    private static final int RADIO_UID = Process.PHONE_UID;
    private static final int LOG_UID = Process.LOG_UID;
    private static final int LOG_UID = Process.LOG_UID;
@@ -281,7 +291,6 @@ public class PackageManagerService extends IPackageManager.Stub {
    final Context mContext;
    final Context mContext;
    final boolean mFactoryTest;
    final boolean mFactoryTest;
    final boolean mOnlyCore;
    final boolean mOnlyCore;
    final boolean mNoDexOpt;
    final DisplayMetrics mMetrics;
    final DisplayMetrics mMetrics;
    final int mDefParseFlags;
    final int mDefParseFlags;
    final String[] mSeparateProcesses;
    final String[] mSeparateProcesses;
@@ -584,6 +593,138 @@ public class PackageManagerService extends IPackageManager.Stub {
    private final String mRequiredVerifierPackage;
    private final String mRequiredVerifierPackage;
    private final PackageUsage mPackageUsage = new PackageUsage();
    private class PackageUsage {
        private static final int WRITE_INTERVAL
            = (DEBUG_DEXOPT) ? 0 : 30*60*1000; // 30m in ms
        private final Object mFileLock = new Object();
        private final AtomicLong mLastWritten = new AtomicLong(0);
        private final AtomicBoolean mBackgroundWriteRunning = new AtomicBoolean(false);
        void write(boolean force) {
            if (force) {
                write();
                return;
            }
            if (SystemClock.elapsedRealtime() - mLastWritten.get() < WRITE_INTERVAL
                && !DEBUG_DEXOPT) {
                return;
            }
            if (mBackgroundWriteRunning.compareAndSet(false, true)) {
                new Thread("PackageUsage_DiskWriter") {
                    public void run() {
                        try {
                            write(true);
                        } finally {
                            mBackgroundWriteRunning.set(false);
                        }
                    }
                }.start();
            }
        }
        private void write() {
            synchronized (mPackages) {
                synchronized (mFileLock) {
                    AtomicFile file = getFile();
                    FileOutputStream f = null;
                    try {
                        f = file.startWrite();
                        BufferedOutputStream out = new BufferedOutputStream(f);
                        FileUtils.setPermissions(file.getBaseFile().getPath(), 0660, SYSTEM_UID, PACKAGE_INFO_GID);
                        StringBuilder sb = new StringBuilder();
                        for (PackageParser.Package pkg : mPackages.values()) {
                            if (pkg.mLastPackageUsageTimeInMills == 0) {
                                continue;
                            }
                            sb.setLength(0);
                            sb.append(pkg.packageName);
                            sb.append(' ');
                            sb.append((long)pkg.mLastPackageUsageTimeInMills);
                            sb.append('\n');
                            out.write(sb.toString().getBytes(StandardCharsets.US_ASCII));
                        }
                        out.flush();
                        file.finishWrite(f);
                    } catch (IOException e) {
                        if (f != null) {
                            file.failWrite(f);
                        }
                        Log.e(TAG, "Failed to write package usage times", e);
                    }
                }
            }
            mLastWritten.set(SystemClock.elapsedRealtime());
        }
        void readLP() {
            synchronized (mFileLock) {
                AtomicFile file = getFile();
                BufferedInputStream in = null;
                try {
                    in = new BufferedInputStream(file.openRead());
                    StringBuffer sb = new StringBuffer();
                    while (true) {
                        String packageName = readToken(in, sb, ' ');
                        if (packageName == null) {
                            break;
                        }
                        String timeInMillisString = readToken(in, sb, '\n');
                        if (timeInMillisString == null) {
                            throw new IOException("Failed to find last usage time for package "
                                                  + packageName);
                        }
                        PackageParser.Package pkg = mPackages.get(packageName);
                        if (pkg == null) {
                            continue;
                        }
                        long timeInMillis;
                        try {
                            timeInMillis = Long.parseLong(timeInMillisString.toString());
                        } catch (NumberFormatException e) {
                            throw new IOException("Failed to parse " + timeInMillisString
                                                  + " as a long.", e);
                        }
                        pkg.mLastPackageUsageTimeInMills = timeInMillis;
                    }
                } catch (FileNotFoundException expected) {
                } catch (IOException e) {
                    Log.w(TAG, "Failed to read package usage times", e);
                } finally {
                    IoUtils.closeQuietly(in);
                }
            }
            mLastWritten.set(SystemClock.elapsedRealtime());
        }
        private String readToken(InputStream in, StringBuffer sb, char endOfToken)
                throws IOException {
            sb.setLength(0);
            while (true) {
                int ch = in.read();
                if (ch == -1) {
                    if (sb.length() == 0) {
                        return null;
                    }
                    throw new IOException("Unexpected EOF");
                }
                if (ch == endOfToken) {
                    return sb.toString();
                }
                sb.append((char)ch);
            }
        }
        private AtomicFile getFile() {
            File dataDir = Environment.getDataDirectory();
            File systemDir = new File(dataDir, "system");
            File fname = new File(systemDir, "package-usage.list");
            return new AtomicFile(fname);
        }
    }
    class PackageHandler extends Handler {
    class PackageHandler extends Handler {
        private boolean mBound = false;
        private boolean mBound = false;
        final ArrayList<HandlerParams> mPendingInstalls =
        final ArrayList<HandlerParams> mPendingInstalls =
@@ -1099,7 +1240,6 @@ public class PackageManagerService extends IPackageManager.Stub {
        mContext = context;
        mContext = context;
        mFactoryTest = factoryTest;
        mFactoryTest = factoryTest;
        mOnlyCore = onlyCore;
        mOnlyCore = onlyCore;
        mNoDexOpt = "eng".equals(SystemProperties.get("ro.build.type"));
        mMetrics = new DisplayMetrics();
        mMetrics = new DisplayMetrics();
        mSettings = new Settings(context);
        mSettings = new Settings(context);
        mSettings.addSharedUserLPw("android.uid.system", Process.SYSTEM_UID,
        mSettings.addSharedUserLPw("android.uid.system", Process.SYSTEM_UID,
@@ -1181,10 +1321,6 @@ public class PackageManagerService extends IPackageManager.Stub {
            // Set flag to monitor and not change apk file paths when
            // Set flag to monitor and not change apk file paths when
            // scanning install directories.
            // scanning install directories.
            int scanMode = SCAN_MONITOR | SCAN_NO_PATHS | SCAN_DEFER_DEX | SCAN_BOOTING;
            int scanMode = SCAN_MONITOR | SCAN_NO_PATHS | SCAN_DEFER_DEX | SCAN_BOOTING;
            if (mNoDexOpt) {
                Slog.w(TAG, "Running ENG build: no pre-dexopt!");
                scanMode |= SCAN_NO_DEX;
            }
            final HashSet<String> alreadyDexOpted = new HashSet<String>();
            final HashSet<String> alreadyDexOpted = new HashSet<String>();
@@ -1203,7 +1339,7 @@ public class PackageManagerService extends IPackageManager.Stub {
                Slog.w(TAG, "No BOOTCLASSPATH found!");
                Slog.w(TAG, "No BOOTCLASSPATH found!");
            }
            }
            boolean didDexOpt = false;
            boolean didDexOptLibraryOrTool = false;
            final List<String> instructionSets = getAllInstructionSets();
            final List<String> instructionSets = getAllInstructionSets();
@@ -1223,13 +1359,12 @@ public class PackageManagerService extends IPackageManager.Stub {
                        }
                        }
                        try {
                        try {
                            if (dalvik.system.DexFile.isDexOptNeededInternal(
                            if (DexFile.isDexOptNeededInternal(lib, null, instructionSet, false)) {
                                    lib, null, instructionSet, false)) {
                                alreadyDexOpted.add(lib);
                                alreadyDexOpted.add(lib);
                                // The list of "shared libraries" we have at this point is
                                // The list of "shared libraries" we have at this point is
                                mInstaller.dexopt(lib, Process.SYSTEM_UID, true, instructionSet);
                                mInstaller.dexopt(lib, Process.SYSTEM_UID, true, instructionSet);
                                didDexOpt = true;
                                didDexOptLibraryOrTool = true;
                            }
                            }
                        } catch (FileNotFoundException e) {
                        } catch (FileNotFoundException e) {
                            Slog.w(TAG, "Library not found: " + lib);
                            Slog.w(TAG, "Library not found: " + lib);
@@ -1275,9 +1410,9 @@ public class PackageManagerService extends IPackageManager.Stub {
                            continue;
                            continue;
                        }
                        }
                        try {
                        try {
                            if (dalvik.system.DexFile.isDexOptNeededInternal(path, null, instructionSet, false)) {
                            if (DexFile.isDexOptNeededInternal(path, null, instructionSet, false)) {
                                mInstaller.dexopt(path, Process.SYSTEM_UID, true, instructionSet);
                                mInstaller.dexopt(path, Process.SYSTEM_UID, true, instructionSet);
                                didDexOpt = true;
                                didDexOptLibraryOrTool = true;
                            }
                            }
                        } catch (FileNotFoundException e) {
                        } catch (FileNotFoundException e) {
                            Slog.w(TAG, "Jar not found: " + path);
                            Slog.w(TAG, "Jar not found: " + path);
@@ -1288,7 +1423,7 @@ public class PackageManagerService extends IPackageManager.Stub {
                }
                }
            }
            }
            if (didDexOpt) {
            if (didDexOptLibraryOrTool) {
                pruneDexFiles(new File(dataDir, "dalvik-cache"));
                pruneDexFiles(new File(dataDir, "dalvik-cache"));
            }
            }
@@ -1459,12 +1594,15 @@ public class PackageManagerService extends IPackageManager.Stub {
            // the correct library paths.
            // the correct library paths.
            updateAllSharedLibrariesLPw();
            updateAllSharedLibrariesLPw();
            for (SharedUserSetting setting : mSettings.getAllSharedUsersLPw()) {
            for (SharedUserSetting setting : mSettings.getAllSharedUsersLPw()) {
                adjustCpuAbisForSharedUserLPw(setting.packages, true /* do dexopt */,
                adjustCpuAbisForSharedUserLPw(setting.packages, true /* do dexopt */,
                        false /* force dexopt */, false /* defer dexopt */);
                        false /* force dexopt */, false /* defer dexopt */);
            }
            }
            // Now that we know all the packages we are keeping,
            // read and update their last usage times.
            mPackageUsage.readLP();
            EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SCAN_END,
            EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SCAN_END,
                    SystemClock.uptimeMillis());
                    SystemClock.uptimeMillis());
            Slog.i(TAG, "Time to scan packages: "
            Slog.i(TAG, "Time to scan packages: "
@@ -1520,6 +1658,14 @@ public class PackageManagerService extends IPackageManager.Stub {
        //
        //
        // Additionally, delete all dex files from the root directory
        // Additionally, delete all dex files from the root directory
        // since there shouldn't be any there anyway.
        // since there shouldn't be any there anyway.
        //
        // Note: This isn't as good an indicator as it used to be. It
        // used to include the boot classpath but at some point
        // DexFile.isDexOptNeeded started returning false for the boot
        // class path files in all cases. It is very possible in a
        // small maintenance release update that the library and tool
        // jars may be unchanged but APK could be removed resulting in
        // unused dalvik-cache files.
        File[] files = cacheDir.listFiles();
        File[] files = cacheDir.listFiles();
        if (files != null) {
        if (files != null) {
            for (File file : files) {
            for (File file : files) {
@@ -3955,21 +4101,60 @@ public class PackageManagerService extends IPackageManager.Stub {
        }
        }
        if (pkgs != null) {
        if (pkgs != null) {
            // Filter out packages that aren't recently used.
            //
            // The exception is first boot of a non-eng device, which
            // should do a full dexopt.
            boolean eng = "eng".equals(SystemProperties.get("ro.build.type"));
            if (eng || !isFirstBoot()) {
                // TODO: add a property to control this?
                long dexOptLRUThresholdInMinutes;
                if (eng) {
                    dexOptLRUThresholdInMinutes = 30; // only last 30 minutes of apps for eng builds.
                } else {
                    dexOptLRUThresholdInMinutes = 7 * 24 * 60; // apps used in the 7 days for users.
                }
                long dexOptLRUThresholdInMills = dexOptLRUThresholdInMinutes * 60 * 1000;
                int total = pkgs.size();
                int skipped = 0;
                long now = System.currentTimeMillis();
                for (Iterator<PackageParser.Package> i = pkgs.iterator(); i.hasNext();) {
                    PackageParser.Package pkg = i.next();
                    long then = pkg.mLastPackageUsageTimeInMills;
                    if (then + dexOptLRUThresholdInMills < now) {
                        if (DEBUG_DEXOPT) {
                            Log.i(TAG, "Skipping dexopt of " + pkg.packageName + " last resumed: " +
                                  ((then == 0) ? "never" : new Date(then)));
                        }
                        i.remove();
                        skipped++;
                    }
                }
                if (DEBUG_DEXOPT) {
                    Log.i(TAG, "Skipped optimizing " + skipped + " of " + total);
                }
            }
            int i = 0;
            int i = 0;
            for (PackageParser.Package pkg : pkgs) {
            for (PackageParser.Package pkg : pkgs) {
                if (!isFirstBoot()) {
                i++;
                i++;
                if (DEBUG_DEXOPT) {
                    Log.i(TAG, "Optimizing app " + i + " of " + pkgs.size()
                          + ": " + pkg.packageName);
                }
                if (!isFirstBoot()) {
                    try {
                    try {
                        ActivityManagerNative.getDefault().showBootMessage(
                        ActivityManagerNative.getDefault().showBootMessage(
                                mContext.getResources().getString(
                                mContext.getResources().getString(
                                        com.android.internal.R.string.android_upgrading_apk,
                                        R.string.android_upgrading_apk,
                                        i, pkgs.size()), true);
                                        i, pkgs.size()), true);
                    } catch (RemoteException e) {
                    } catch (RemoteException e) {
                    }
                    }
                }
                }
                PackageParser.Package p = pkg;
                PackageParser.Package p = pkg;
                synchronized (mInstallLock) {
                synchronized (mInstallLock) {
                    if (!p.mDidDexOpt) {
                    if (p.mDexOptNeeded) {
                        performDexOptLI(p, false /* force dex */, false /* defer */,
                        performDexOptLI(p, false /* force dex */, false /* defer */,
                                true /* include dependencies */);
                                true /* include dependencies */);
                    }
                    }
@@ -3981,25 +4166,32 @@ public class PackageManagerService extends IPackageManager.Stub {
    @Override
    @Override
    public boolean performDexOpt(String packageName) {
    public boolean performDexOpt(String packageName) {
        enforceSystemOrRoot("Only the system can request dexopt be performed");
        enforceSystemOrRoot("Only the system can request dexopt be performed");
        if (!mNoDexOpt) {
            return false;
        }
        PackageParser.Package p;
        PackageParser.Package p;
        synchronized (mPackages) {
        synchronized (mPackages) {
            p = mPackages.get(packageName);
            p = mPackages.get(packageName);
            if (p == null || p.mDidDexOpt) {
            if (p == null) {
                return false;
            }
            p.mLastPackageUsageTimeInMills = System.currentTimeMillis();
            mPackageUsage.write();
            if (!p.mDexOptNeeded) {
                return false;
                return false;
            }
            }
        }
        }
        synchronized (mInstallLock) {
        synchronized (mInstallLock) {
            return performDexOptLI(p, false /* force dex */, false /* defer */,
            return performDexOptLI(p, false /* force dex */, false /* defer */,
                    true /* include dependencies */) == DEX_OPT_PERFORMED;
                    true /* include dependencies */) == DEX_OPT_PERFORMED;
        }
        }
    }
    }
    private void performDexOptLibsLI(ArrayList<String> libs, String instructionSet, boolean forceDex,
    public void shutdown() {
            boolean defer, HashSet<String> done) {
        mPackageUsage.write(true);
    }
    private void performDexOptLibsLI(ArrayList<String> libs, String instructionSet,
             boolean forceDex, boolean defer, HashSet<String> done) {
        for (int i=0; i<libs.size(); i++) {
        for (int i=0; i<libs.size(); i++) {
            PackageParser.Package libPkg;
            PackageParser.Package libPkg;
            String libName;
            String libName;
@@ -4024,8 +4216,7 @@ public class PackageManagerService extends IPackageManager.Stub {
    static final int DEX_OPT_FAILED = -1;
    static final int DEX_OPT_FAILED = -1;
    private int performDexOptLI(PackageParser.Package pkg, String instructionSetOverride,
    private int performDexOptLI(PackageParser.Package pkg, String instructionSetOverride,
            boolean forceDex,
            boolean forceDex, boolean defer, HashSet<String> done) {
            boolean defer, HashSet<String> done) {
        final String instructionSet = instructionSetOverride != null ?
        final String instructionSet = instructionSetOverride != null ?
                instructionSetOverride : getAppInstructionSet(pkg.applicationInfo);
                instructionSetOverride : getAppInstructionSet(pkg.applicationInfo);
@@ -4042,47 +4233,52 @@ public class PackageManagerService extends IPackageManager.Stub {
        boolean performed = false;
        boolean performed = false;
        if ((pkg.applicationInfo.flags&ApplicationInfo.FLAG_HAS_CODE) != 0) {
        if ((pkg.applicationInfo.flags&ApplicationInfo.FLAG_HAS_CODE) != 0) {
            String path = pkg.mScanPath;
            String path = pkg.mScanPath;
            int ret = 0;
            try {
            try {
                if (forceDex || dalvik.system.DexFile.isDexOptNeededInternal(path,
                boolean isDexOptNeededInternal = DexFile.isDexOptNeededInternal(path,
                        pkg.packageName, instructionSet, defer)) {
                                                                                pkg.packageName,
                    if (!forceDex && defer) {
                                                                                instructionSet,
                                                                                defer);
                // There are three basic cases here:
                // 1.) we need to dexopt, either because we are forced or it is needed
                // 2.) we are defering a needed dexopt
                // 3.) we are skipping an unneeded dexopt
                if (forceDex || (!defer && isDexOptNeededInternal)) {
                    Log.i(TAG, "Running dexopt on: " + pkg.applicationInfo.packageName);
                    final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid);
                    int ret = mInstaller.dexopt(path, sharedGid, !isForwardLocked(pkg),
                                                pkg.packageName, instructionSet);
                    // Note that we ran dexopt, since rerunning will
                    // probably just result in an error again.
                    pkg.mDexOptNeeded = false;
                    if (ret < 0) {
                        return DEX_OPT_FAILED;
                    }
                    return DEX_OPT_PERFORMED;
                }
                if (defer && isDexOptNeededInternal) {
                    if (mDeferredDexOpt == null) {
                    if (mDeferredDexOpt == null) {
                        mDeferredDexOpt = new HashSet<PackageParser.Package>();
                        mDeferredDexOpt = new HashSet<PackageParser.Package>();
                    }
                    }
                    mDeferredDexOpt.add(pkg);
                    mDeferredDexOpt.add(pkg);
                    return DEX_OPT_DEFERRED;
                    return DEX_OPT_DEFERRED;
                    } else {
                        Log.i(TAG, "Running dexopt on: " + pkg.applicationInfo.packageName +
                                " (instructionSet=" + instructionSet + ")");
                        final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid);
                        ret = mInstaller.dexopt(path, sharedGid, !isForwardLocked(pkg),
                                                pkg.packageName, instructionSet);
                        pkg.mDidDexOpt = true;
                        performed = true;
                    }
                }
                }
                pkg.mDexOptNeeded = false;
                return DEX_OPT_SKIPPED;
            } catch (FileNotFoundException e) {
            } catch (FileNotFoundException e) {
                Slog.w(TAG, "Apk not found for dexopt: " + path);
                Slog.w(TAG, "Apk not found for dexopt: " + path);
                ret = -1;
                return DEX_OPT_FAILED;
            } catch (IOException e) {
            } catch (IOException e) {
                Slog.w(TAG, "IOException reading apk: " + path, e);
                Slog.w(TAG, "IOException reading apk: " + path, e);
                ret = -1;
                return DEX_OPT_FAILED;
            } catch (dalvik.system.StaleDexCacheError e) {
            } catch (StaleDexCacheError e) {
                Slog.w(TAG, "StaleDexCacheError when reading apk: " + path, e);
                Slog.w(TAG, "StaleDexCacheError when reading apk: " + path, e);
                ret = -1;
                return DEX_OPT_FAILED;
            } catch (Exception e) {
            } catch (Exception e) {
                Slog.w(TAG, "Exception when doing dexopt : ", e);
                Slog.w(TAG, "Exception when doing dexopt : ", e);
                ret = -1;
            }
            if (ret < 0) {
                //error from installer
                return DEX_OPT_FAILED;
                return DEX_OPT_FAILED;
            }
            }
        }
        }
        return DEX_OPT_SKIPPED;
        return performed ? DEX_OPT_PERFORMED : DEX_OPT_SKIPPED;
    }
    }
    private String getAppInstructionSet(ApplicationInfo info) {
    private String getAppInstructionSet(ApplicationInfo info) {
@@ -4371,7 +4567,7 @@ public class PackageManagerService extends IPackageManager.Stub {
                    mResolveActivity.processName = "system:ui";
                    mResolveActivity.processName = "system:ui";
                    mResolveActivity.launchMode = ActivityInfo.LAUNCH_MULTIPLE;
                    mResolveActivity.launchMode = ActivityInfo.LAUNCH_MULTIPLE;
                    mResolveActivity.flags = ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS;
                    mResolveActivity.flags = ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS;
                    mResolveActivity.theme = com.android.internal.R.style.Theme_Holo_Dialog_Alert;
                    mResolveActivity.theme = R.style.Theme_Holo_Dialog_Alert;
                    mResolveActivity.exported = true;
                    mResolveActivity.exported = true;
                    mResolveActivity.enabled = true;
                    mResolveActivity.enabled = true;
                    mResolveInfo.activityInfo = mResolveActivity;
                    mResolveInfo.activityInfo = mResolveActivity;
@@ -9287,22 +9483,22 @@ public class PackageManagerService extends IPackageManager.Stub {
    // Utility method used to move dex files during install.
    // Utility method used to move dex files during install.
    private int moveDexFilesLI(PackageParser.Package newPackage) {
    private int moveDexFilesLI(PackageParser.Package newPackage) {
        int retCode;
        if ((newPackage.applicationInfo.flags&ApplicationInfo.FLAG_HAS_CODE) != 0) {
        if ((newPackage.applicationInfo.flags&ApplicationInfo.FLAG_HAS_CODE) != 0) {
            retCode = mInstaller.movedex(newPackage.mScanPath, newPackage.mPath,
            final String instructionSet = getAppInstructionSet(newPackage.applicationInfo);
                    getAppInstructionSet(newPackage.applicationInfo));
            int retCode = mInstaller.movedex(newPackage.mScanPath, newPackage.mPath,
                                             instructionSet);
            if (retCode != 0) {
            if (retCode != 0) {
                if (mNoDexOpt) {
                /*
                /*
                     * If we're in an engineering build, programs are lazily run
                 * Programs may be lazily run through dexopt, so the
                     * through dexopt. If the .dex file doesn't exist yet, it
                 * source may not exist. However, something seems to
                     * will be created when the program is run next.
                 * have gone wrong, so note that dexopt needs to be
                 * run again and remove the source file. In addition,
                 * remove the target to make sure there isn't a stale
                 * file from a previous version of the package.
                 */
                 */
                    Slog.i(TAG, "dex file doesn't exist, skipping move: " + newPackage.mPath);
                newPackage.mDexOptNeeded = true;
                } else {
                mInstaller.rmdex(newPackage.mScanPath, instructionSet);
                    Slog.e(TAG, "Couldn't rename dex file: " + newPackage.mPath);
                mInstaller.rmdex(newPackage.mPath, instructionSet);
                    return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
                }
            }
            }
        }
        }
        return PackageManager.INSTALL_SUCCEEDED;
        return PackageManager.INSTALL_SUCCEEDED;