Fix targetSdkVersion, make resize mode a flag, delayed dexopt, easy ApplicationInfo.

- Fix a bug where targetSdkVersion could not be set if minSdkVersion.  Stupid, stupid.
  Also make sure to fail if minSdkVersion is for a code name.  Really stupid.

- Change the API for resize compatibility mode to be a bit in the flags field, instead
  of a separate boolean.

- Implement delayed dexopting, to avoid the looong full dexopt during boot.  This is
  only enabled for "eng" builds.  When in this mode, the activity manager will make
  sure that a dexopt has been done before loading an .apk into a process, and will
  try to avoid displaying ANRs if they are due to the dexopt causing some operation
  to take longer than it normally would (though I make no guarantees about this
  totally working).

- Add API to Context to get the ApplicationInfo for its package, for easy access to
  things like targetSdkVersion.
diff --git a/api/current.xml b/api/current.xml
index 4efc71f..95c396f 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -27473,6 +27473,17 @@
  visibility="public"
 >
 </method>
+<method name="getApplicationInfo"
+ return="android.content.pm.ApplicationInfo"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="getAssets"
  return="android.content.res.AssetManager"
  abstract="true"
@@ -28825,6 +28836,17 @@
  visibility="public"
 >
 </method>
+<method name="getApplicationInfo"
+ return="android.content.pm.ApplicationInfo"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="getAssets"
  return="android.content.res.AssetManager"
  abstract="false"
@@ -35185,6 +35207,17 @@
  visibility="public"
 >
 </field>
+<field name="FLAG_SUPPORTS_LARGE_SCREENS"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="512"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="FLAG_SYSTEM"
  type="int"
  transient="false"
@@ -35258,16 +35291,6 @@
  visibility="public"
 >
 </field>
-<field name="expandable"
- type="boolean"
- transient="false"
- volatile="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
 <field name="flags"
  type="int"
  transient="false"
@@ -37127,17 +37150,6 @@
  visibility="public"
 >
 </field>
-<field name="GET_EXPANDABLE"
- type="int"
- transient="false"
- volatile="false"
- value="131072"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
 <field name="GET_GIDS"
  type="int"
  transient="false"
@@ -114387,6 +114399,17 @@
  visibility="public"
 >
 </method>
+<method name="getApplicationInfo"
+ return="android.content.pm.ApplicationInfo"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="getAssets"
  return="android.content.res.AssetManager"
  abstract="false"
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 477badb..6873379 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -187,7 +187,7 @@
             try {
                 appInfo = getPackageManager().getApplicationInfo(
                         pkgInfo.getPackageName(),
-                        PackageManager.GET_SUPPORTS_DENSITIES | PackageManager.GET_EXPANDABLE);
+                        PackageManager.GET_SUPPORTS_DENSITIES);
             } catch (RemoteException e) {
                 throw new AssertionError(e);
             }
@@ -287,6 +287,10 @@
             return mPackageName;
         }
 
+        public ApplicationInfo getApplicationInfo() {
+            return mApplicationInfo;
+        }
+        
         public boolean isSecurityViolation() {
             return mSecurityViolation;
         }
diff --git a/core/java/android/app/ApplicationContext.java b/core/java/android/app/ApplicationContext.java
index 23daf12..bbad8f4 100644
--- a/core/java/android/app/ApplicationContext.java
+++ b/core/java/android/app/ApplicationContext.java
@@ -283,6 +283,14 @@
     }
 
     @Override
+    public ApplicationInfo getApplicationInfo() {
+        if (mPackageInfo != null) {
+            return mPackageInfo.getApplicationInfo();
+        }
+        throw new RuntimeException("Not supported in system context");
+    }
+
+    @Override
     public String getPackageResourcePath() {
         if (mPackageInfo != null) {
             return mPackageInfo.getResDir();
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 925249e..b0396f6 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -16,6 +16,7 @@
 
 package android.content;
 
+import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.res.AssetManager;
 import android.content.res.Resources;
@@ -233,6 +234,9 @@
     /** Return the name of this application's package. */
     public abstract String getPackageName();
 
+    /** Return the full application info for this context's package. */
+    public abstract ApplicationInfo getApplicationInfo();
+    
     /**
      * {@hide}
      * Return the full path to this context's resource files.  This is the ZIP files
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index 262204e..7513b3b 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -16,6 +16,7 @@
 
 package android.content;
 
+import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.res.AssetManager;
 import android.content.res.Resources;
@@ -120,6 +121,11 @@
     }
 
     @Override
+    public ApplicationInfo getApplicationInfo() {
+        return mBase.getApplicationInfo();
+    }
+    
+    @Override
     public String getPackageResourcePath() {
         return mBase.getPackageResourcePath();
     }
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index f10dd53..2a2cf93 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -137,6 +137,13 @@
     public static final int FLAG_TEST_ONLY = 1<<8;
 
     /**
+     * Value for {@link #flags}: true when the application's window can be
+     * expanded over default window size in target density (320x480 for
+     * 1.0 density, 480x720 for 1.5 density etc)
+     */
+    public static final int FLAG_SUPPORTS_LARGE_SCREENS = 1<<9;
+    
+    /**
      * Value for {@link #flags}: this is false if the application has set
      * its android:allowBackup to false, true otherwise.
      * 
@@ -201,12 +208,6 @@
     public int[] supportsDensities;
 
     /**
-     * True when the application's window can be expanded over default window
-     * size in target density (320x480 for 1.0 density, 480x720 for 1.5 density etc)
-     */
-    public boolean expandable = false;
-
-    /**
      * The minimum SDK version this application targets.  It may run on earilier
      * versions, but it knows how to work with any new behavior added at this
      * version.  Will be {@link android.os.Build.VERSION_CODES#CUR_DEVELOPMENT}
@@ -240,7 +241,6 @@
         pw.println(prefix + "manageSpaceActivityName="+manageSpaceActivityName);
         pw.println(prefix + "description=0x"+Integer.toHexString(descriptionRes));
         pw.println(prefix + "supportsDensities=" + supportsDensities);
-        pw.println(prefix + "expandable=" + expandable);
         super.dumpBack(pw, prefix);
     }
     
@@ -288,7 +288,6 @@
         manageSpaceActivityName = orig.manageSpaceActivityName;
         descriptionRes = orig.descriptionRes;
         supportsDensities = orig.supportsDensities;
-        expandable = orig.expandable;
     }
 
 
@@ -321,7 +320,6 @@
         dest.writeString(backupAgentName);
         dest.writeInt(descriptionRes);
         dest.writeIntArray(supportsDensities);
-        dest.writeInt(expandable ? 1 : 0);
     }
 
     public static final Parcelable.Creator<ApplicationInfo> CREATOR
@@ -353,7 +351,6 @@
         backupAgentName = source.readString();
         descriptionRes = source.readInt();
         supportsDensities = source.createIntArray();
-        expandable = source.readInt() != 0;
     }
 
     /**
@@ -383,7 +380,7 @@
      * @hide
      */
     public void disableCompatibilityMode() {
-        expandable = true;
+        flags |= FLAG_SUPPORTS_LARGE_SCREENS;
         supportsDensities = ANY_DENSITIES_ARRAY;
     }
 }
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 5656b6b..b33a85b 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -301,4 +301,11 @@
     boolean isSafeMode();
     void systemReady();
     boolean hasSystemUidErrors();
+    
+    /**
+     * 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.
+     */
+    boolean performDexOpt(String packageName);
 }
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index f746a40..e0cad39 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -181,12 +181,6 @@
     public static final int MATCH_DEFAULT_ONLY   = 0x00010000;
 
     /**
-     * {@link ApplicationInfo} flag: return the
-     * {link ApplicationInfo#expandable} boolean flag of the package.
-     */
-    public static final int GET_EXPANDABLE = 0x00020000;
-
-    /**
      * Permission check result: this is returned by {@link #checkPermission}
      * if the permission has been granted to the given package.
      */
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index ab8559c..ab9518e 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -777,7 +777,7 @@
                             targetCode = minCode = val.string.toString();
                         } else {
                             // If it's not a string, it's an integer.
-                            minVers = val.data;
+                            targetVers = minVers = val.data;
                         }
                     }
                     
@@ -798,6 +798,25 @@
 
                     sa.recycle();
 
+                    if (minCode != null) {
+                        if (!minCode.equals(mSdkCodename)) {
+                            if (mSdkCodename != null) {
+                                outError[0] = "Requires development platform " + minCode
+                                        + " (current platform is " + mSdkCodename + ")";
+                            } else {
+                                outError[0] = "Requires development platform " + minCode
+                                        + " but this is a release platform.";
+                            }
+                            mParseError = PackageManager.INSTALL_FAILED_OLDER_SDK;
+                            return null;
+                        }
+                    } else if (minVers > mSdkVersion) {
+                        outError[0] = "Requires newer sdk version #" + minVers
+                                + " (current version is #" + mSdkVersion + ")";
+                        mParseError = PackageManager.INSTALL_FAILED_OLDER_SDK;
+                        return null;
+                    }
+                    
                     if (targetCode != null) {
                         if (!targetCode.equals(mSdkCodename)) {
                             if (mSdkCodename != null) {
@@ -817,13 +836,6 @@
                         pkg.applicationInfo.targetSdkVersion = targetVers;
                     }
                     
-                    if (minVers > mSdkVersion) {
-                        outError[0] = "Requires newer sdk version #" + minVers
-                                + " (current version is #" + mSdkVersion + ")";
-                        mParseError = PackageManager.INSTALL_FAILED_OLDER_SDK;
-                        return null;
-                    }
-                    
                     if (maxVers < mSdkVersion) {
                         outError[0] = "Requires older sdk version #" + maxVers
                                 + " (current version is #" + mSdkVersion + ")";
@@ -865,7 +877,7 @@
                 XmlUtils.skipCurrentTag(parser);
 
             } else if (tagName.equals("expandable")) {
-                pkg.expandable = true;
+                pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS;
                 XmlUtils.skipCurrentTag(parser);
             } else {
                 Log.w(TAG, "Bad element under <manifest>: "
@@ -2262,9 +2274,6 @@
         public final ArrayList<Integer> supportsDensityList = new ArrayList<Integer>();
         public int[] supportsDensities = null;
 
-        // If the application's window is expandable.
-        public boolean expandable;
-        
         // If this is a 3rd party app, this is the path of the zip file.
         public String mPath;
 
@@ -2287,6 +2296,17 @@
         // preferred up order.
         public int mPreferredOrder = 0;
 
+        // For use by package manager service to keep track of which apps
+        // have been installed with forward locking.
+        public boolean mForwardLocked;
+        
+        // For use by the package manager to keep track of the path to the
+        // file an app came from.
+        public String mScanPath;
+        
+        // For use by package manager to keep track of where it has done dexopt.
+        public boolean mDidDexOpt;
+        
         // Additional data supplied by callers.
         public Object mExtras;
         
@@ -2439,9 +2459,6 @@
                 && p.supportsDensities != null) {
             return true;
         }
-        if ((flags & PackageManager.GET_EXPANDABLE) != 0) {
-            return true;
-        }
         return false;
     }
 
@@ -2462,9 +2479,6 @@
         if ((flags & PackageManager.GET_SUPPORTS_DENSITIES) != 0) {
             ai.supportsDensities = p.supportsDensities;
         }
-        if ((flags & PackageManager.GET_EXPANDABLE) != 0) {
-            ai.expandable = p.expandable;
-        }
         return ai;
     }
 
diff --git a/core/java/android/content/res/CompatibilityInfo.java b/core/java/android/content/res/CompatibilityInfo.java
index 836de39..680fef8 100644
--- a/core/java/android/content/res/CompatibilityInfo.java
+++ b/core/java/android/content/res/CompatibilityInfo.java
@@ -69,7 +69,8 @@
     public final boolean mScalingRequired;
 
     public CompatibilityInfo(ApplicationInfo appInfo) {
-        mExpandable = mConfiguredExpandable = appInfo.expandable;
+        mExpandable = mConfiguredExpandable =
+            (appInfo.flags & ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS) != 0;
         
         float packageDensityScale = -1.0f;
         if (appInfo.supportsDensities != null) {
diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java
index f51f3d0..f18d6e0 100644
--- a/services/java/com/android/server/PackageManagerService.java
+++ b/services/java/com/android/server/PackageManagerService.java
@@ -19,7 +19,6 @@
 import com.android.internal.app.ResolverActivity;
 import com.android.internal.util.FastXmlSerializer;
 import com.android.internal.util.XmlUtils;
-import com.android.server.PackageManagerService.PreferredActivity;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
@@ -30,7 +29,6 @@
 import android.app.PendingIntent;
 import android.app.PendingIntent.CanceledException;
 import android.content.ComponentName;
-import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
@@ -152,6 +150,7 @@
     
     final Context mContext;
     final boolean mFactoryTest;
+    final boolean mNoDexOpt;
     final DisplayMetrics mMetrics;
     final int mDefParseFlags;
     final String[] mSeparateProcesses;
@@ -303,6 +302,7 @@
         
         mContext = context;
         mFactoryTest = factoryTest;
+        mNoDexOpt = "eng".equals(SystemProperties.get("ro.build.type"));
         mMetrics = new DisplayMetrics();
         mSettings = new Settings();
         mSettings.addSharedUserLP("android.uid.system",
@@ -372,6 +372,10 @@
                     startTime);
             
             int scanMode = SCAN_MONITOR;
+            if (mNoDexOpt) {
+                Log.w(TAG, "Running ENG build: no pre-dexopt!");
+                scanMode |= SCAN_NO_DEX; 
+            }
             
             final HashSet<String> libFiles = new HashSet<String>();
             
@@ -993,10 +997,11 @@
             if (Config.LOGV) Log.v(TAG, "getActivityInfo " + component + ": " + a);
             if (a != null && mSettings.isEnabledLP(a.info, flags)) {
                 ActivityInfo ainfo = PackageParser.generateActivityInfo(a, flags);
-                if (ainfo != null && (flags & PackageManager.GET_EXPANDABLE) != 0) {
+                if (ainfo != null) {
                     ApplicationInfo appInfo = getApplicationInfo(component.getPackageName(),
-                            PackageManager.GET_EXPANDABLE | PackageManager.GET_SUPPORTS_DENSITIES); 
-                    if (appInfo != null && !appInfo.expandable) {
+                            PackageManager.GET_SUPPORTS_DENSITIES);
+                    if (appInfo != null &&
+                            (appInfo.flags & ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS) == 0) {
                         // Check if the screen size is same as what the application expect.
                         CompatibilityInfo info = new CompatibilityInfo(appInfo);
                         DisplayMetrics metrics = new DisplayMetrics();
@@ -1009,11 +1014,13 @@
                             // Don't allow an app that cannot expand to handle rotation.
                             ainfo.configChanges &= ~ ActivityInfo.CONFIG_ORIENTATION;
                         } else {
-                            appInfo.expandable = true;
+                            appInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS;
                         }
                         if (DEBUG_SETTINGS) {
                             Log.d(TAG, "component=" + component +
-                                    ", expandable:" + appInfo.expandable);
+                                    ", expandable:" +
+                                    ((appInfo.flags &
+                                            ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS) != 0));
                         }
                     }
                 }
@@ -1943,7 +1950,56 @@
         }
         return true;
     }
+    
+    public boolean performDexOpt(String packageName) {
+        if (!mNoDexOpt) {
+            return false;
+        }
         
+        PackageParser.Package p;
+        synchronized (mPackages) {
+            p = mPackages.get(packageName);
+            if (p == null || p.mDidDexOpt) {
+                return false;
+            }
+        }
+        synchronized (mInstallLock) {
+            return performDexOptLI(p, false) == DEX_OPT_PERFORMED;
+        }
+    }
+    
+    static final int DEX_OPT_SKIPPED = 0;
+    static final int DEX_OPT_PERFORMED = 1;
+    static final int DEX_OPT_FAILED = -1;
+    
+    private int performDexOptLI(PackageParser.Package pkg, boolean forceDex) {
+        boolean performed = false;
+        if ((pkg.applicationInfo.flags&ApplicationInfo.FLAG_HAS_CODE) != 0) {
+            String path = pkg.mScanPath;
+            int ret = 0;
+            try {
+                if (forceDex || dalvik.system.DexFile.isDexOptNeeded(path)) {
+                    ret = mInstaller.dexopt(path, pkg.applicationInfo.uid, 
+                            !pkg.mForwardLocked);
+                    pkg.mDidDexOpt = true;
+                    performed = true;
+                }
+            } catch (FileNotFoundException e) {
+                Log.w(TAG, "Apk not found for dexopt: " + path);
+                ret = -1;
+            } catch (IOException e) {
+                Log.w(TAG, "Exception reading apk: " + path, e);
+                ret = -1;
+            }
+            if (ret < 0) {
+                //error from installer
+                return DEX_OPT_FAILED;
+            }
+        }
+        
+        return performed ? DEX_OPT_PERFORMED : DEX_OPT_SKIPPED;
+    }
+    
     private PackageParser.Package scanPackageLI(
         File scanFile, File destCodeFile, File destResourceFile,
         PackageParser.Package pkg, int parseFlags, int scanMode) {
@@ -2239,23 +2295,11 @@
                 }
             }
 
-            if ((scanMode&SCAN_NO_DEX) == 0
-                    && (pkg.applicationInfo.flags&ApplicationInfo.FLAG_HAS_CODE) != 0) {
-                int ret = 0;
-                try {
-                    if (forceDex || dalvik.system.DexFile.isDexOptNeeded(path)) {
-                        ret = mInstaller.dexopt(path, pkg.applicationInfo.uid, 
-                                (scanMode&SCAN_FORWARD_LOCKED) == 0);
-                    }
-                } catch (FileNotFoundException e) {
-                    Log.w(TAG, "Apk not found for dexopt: " + path);
-                    ret = -1;
-                } catch (IOException e) {
-                    Log.w(TAG, "Exception reading apk: " + path, e);
-                    ret = -1;
-                }
-                if (ret < 0) {
-                    //error from installer
+            pkg.mForwardLocked = (scanMode&SCAN_FORWARD_LOCKED) != 0;
+            pkg.mScanPath = path;
+            
+            if ((scanMode&SCAN_NO_DEX) == 0) {
+                if (performDexOptLI(pkg, forceDex) == DEX_OPT_FAILED) {
                     mLastScanError = PackageManager.INSTALL_FAILED_DEXOPT;
                     return null;
                 }
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 045e636..8cf1cc2 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -181,7 +181,7 @@
 
     // The flags that are set for all calls we make to the package manager.
     static final int STOCK_PM_FLAGS = PackageManager.GET_SHARED_LIBRARY_FILES
-            | PackageManager.GET_SUPPORTS_DENSITIES | PackageManager.GET_EXPANDABLE;
+            | PackageManager.GET_SUPPORTS_DENSITIES;
     
     private static final String SYSTEM_SECURE = "ro.secure";
 
@@ -809,6 +809,12 @@
      */
     int[] mProcDeaths = new int[20];
     
+    /**
+     * 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.
+     */
+    boolean mDidDexOpt;
+    
     String mDebugApp = null;
     boolean mWaitForDebugger = false;
     boolean mDebugTransient = false;
@@ -1007,6 +1013,12 @@
                 processNextBroadcast(true);
             } break;
             case BROADCAST_TIMEOUT_MSG: {
+                if (mDidDexOpt) {
+                    mDidDexOpt = false;
+                    Message nmsg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
+                    mHandler.sendMessageDelayed(nmsg, BROADCAST_TIMEOUT);
+                    return;
+                }
                 broadcastTimeout();
             } break;
             case PAUSE_TIMEOUT_MSG: {
@@ -1017,9 +1029,16 @@
                 activityPaused(token, null, true);
             } break;
             case IDLE_TIMEOUT_MSG: {
-                IBinder token = (IBinder)msg.obj;
+                if (mDidDexOpt) {
+                    mDidDexOpt = false;
+                    Message nmsg = mHandler.obtainMessage(IDLE_TIMEOUT_MSG);
+                    nmsg.obj = msg.obj;
+                    mHandler.sendMessageDelayed(nmsg, IDLE_TIMEOUT);
+                    return;
+                }
                 // We don't at this point know if the activity is fullscreen,
                 // so we need to be conservative and assume it isn't.
+                IBinder token = (IBinder)msg.obj;
                 Log.w(TAG, "Activity idle timeout for " + token);
                 activityIdleInternal(token, true);
             } break;
@@ -1035,6 +1054,13 @@
                 activityIdle(token);
             } break;
             case SERVICE_TIMEOUT_MSG: {
+                if (mDidDexOpt) {
+                    mDidDexOpt = false;
+                    Message nmsg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
+                    nmsg.obj = msg.obj;
+                    mHandler.sendMessageDelayed(nmsg, SERVICE_TIMEOUT);
+                    return;
+                }
                 serviceTimeout((ProcessRecord)msg.obj);
             } break;
             case UPDATE_TIME_ZONE: {
@@ -1071,6 +1097,12 @@
                 }
             } break;
             case LAUNCH_TIMEOUT_MSG: {
+                if (mDidDexOpt) {
+                    mDidDexOpt = false;
+                    Message nmsg = mHandler.obtainMessage(LAUNCH_TIMEOUT_MSG);
+                    mHandler.sendMessageDelayed(nmsg, LAUNCH_TIMEOUT);
+                    return;
+                }
                 synchronized (ActivityManagerService.this) {
                     if (mLaunchingActivity.isHeld()) {
                         Log.w(TAG, "Launch timeout has expired, giving up wake lock!");
@@ -1091,6 +1123,13 @@
                 }
             }
             case PROC_START_TIMEOUT_MSG: {
+                if (mDidDexOpt) {
+                    mDidDexOpt = false;
+                    Message nmsg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
+                    nmsg.obj = msg.obj;
+                    mHandler.sendMessageDelayed(nmsg, PROC_START_TIMEOUT);
+                    return;
+                }
                 ProcessRecord app = (ProcessRecord)msg.obj;
                 synchronized (ActivityManagerService.this) {
                     processStartTimedOutLocked(app);
@@ -1607,6 +1646,16 @@
         return proc;
     }
 
+    private void ensurePackageDexOpt(String packageName) {
+        IPackageManager pm = ActivityThread.getPackageManager();
+        try {
+            if (pm.performDexOpt(packageName)) {
+                mDidDexOpt = true;
+            }
+        } catch (RemoteException e) {
+        }
+    }
+    
     private boolean isNextTransitionForward() {
         int transit = mWindowManager.getPendingAppTransition();
         return transit == WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
@@ -1666,6 +1715,7 @@
             if (r.isHomeActivity) {
                 mHomeProcess = app;
             }
+            ensurePackageDexOpt(r.intent.getComponent().getPackageName());
             app.thread.scheduleLaunchActivity(new Intent(r.intent), r,
                     r.info, r.icicle, results, newIntents, !andResume,
                     isNextTransitionForward());
@@ -4819,6 +4869,10 @@
                 isRestrictedBackupMode = (mBackupTarget.backupMode == BackupRecord.RESTORE)
                         || (mBackupTarget.backupMode == BackupRecord.BACKUP_FULL);
             }
+            ensurePackageDexOpt(app.info.packageName);
+            if (app.instrumentationInfo != null) {
+                ensurePackageDexOpt(app.instrumentationInfo.packageName);
+            }
             thread.bindApplication(processName, app.instrumentationInfo != null
                     ? app.instrumentationInfo : app.info, providers,
                     app.instrumentationClass, app.instrumentationProfileFile,
@@ -4907,6 +4961,7 @@
         // Check whether the next backup agent is in this process...
         if (!badApp && mBackupTarget != null && mBackupTarget.appInfo.uid == app.info.uid) {
             if (DEBUG_BACKUP) Log.v(TAG, "New app is backup target, launching agent for " + app);
+            ensurePackageDexOpt(mBackupTarget.appInfo.packageName);
             try {
                 thread.scheduleCreateBackupAgent(mBackupTarget.appInfo, mBackupTarget.backupMode);
             } catch (Exception e) {
@@ -6918,6 +6973,7 @@
                 }
                 app.pubProviders.put(cpi.name, cpr);
                 app.addPackage(cpi.applicationInfo.packageName);
+                ensurePackageDexOpt(cpi.applicationInfo.packageName);
             }
         }
         return providers;
@@ -9542,6 +9598,7 @@
             synchronized (r.stats.getBatteryStats()) {
                 r.stats.startLaunchedLocked();
             }
+            ensurePackageDexOpt(r.serviceInfo.packageName);
             app.thread.scheduleCreateService(r, r.serviceInfo);
             created = true;
         } finally {
@@ -11098,6 +11155,7 @@
             if (DEBUG_BROADCAST_LIGHT) Log.v(TAG,
                     "Delivering to component " + r.curComponent
                     + ": " + r);
+            ensurePackageDexOpt(r.intent.getComponent().getPackageName());
             app.thread.scheduleReceiver(new Intent(r.intent), r.curReceiver,
                     r.resultCode, r.resultData, r.resultExtras, r.ordered);
             started = true;
diff --git a/services/java/com/android/server/am/HistoryRecord.java b/services/java/com/android/server/am/HistoryRecord.java
index 944ea02..b3fc313 100644
--- a/services/java/com/android/server/am/HistoryRecord.java
+++ b/services/java/com/android/server/am/HistoryRecord.java
@@ -463,6 +463,12 @@
                     return false;
                 }
                 
+                if (service.mDidDexOpt) {
+                    // Give more time since we were dexopting.
+                    service.mDidDexOpt = false;
+                    return false;
+                }
+                
                 if (r.app.instrumentationClass == null) { 
                     service.appNotRespondingLocked(r.app, r, "keyDispatchingTimedOut");
                 } else {
diff --git a/test-runner/android/test/mock/MockContext.java b/test-runner/android/test/mock/MockContext.java
index 9e0cf2c..efc4880 100644
--- a/test-runner/android/test/mock/MockContext.java
+++ b/test-runner/android/test/mock/MockContext.java
@@ -24,6 +24,7 @@
 import android.content.BroadcastReceiver;
 import android.content.ServiceConnection;
 import android.content.SharedPreferences;
+import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.res.AssetManager;
 import android.content.res.Resources;
@@ -100,6 +101,11 @@
     }
 
     @Override
+    public ApplicationInfo getApplicationInfo() {
+        throw new UnsupportedOperationException();
+    }
+    
+    @Override
     public String getPackageResourcePath() {
         throw new UnsupportedOperationException();
     }
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeContext.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeContext.java
index d0896b5..69f3d9c 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeContext.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeContext.java
@@ -29,6 +29,7 @@
 import android.content.IntentFilter;
 import android.content.ServiceConnection;
 import android.content.SharedPreferences;
+import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.res.AssetManager;
 import android.content.res.Configuration;
@@ -960,6 +961,12 @@
     }
 
     @Override
+    public ApplicationInfo getApplicationInfo() {
+        // TODO Auto-generated method stub
+        return null;
+    }
+    
+    @Override
     public String getPackageResourcePath() {
         // TODO Auto-generated method stub
         return null;