Add progress dialog for booting after an upgrade.

This introduces a new facility for code during the boot process
to display messages to the user through a progress dialog.  This
is only for use when performing longer-than-usual post-upgrade
operations such as running dexopt on applications or upgrading
databases.

Change-Id: I0e78439ccec3850fb67872c22f235bf12a158dae
diff --git a/services/java/com/android/server/DropBoxManagerService.java b/services/java/com/android/server/DropBoxManagerService.java
index 5c878c9..d37c9ab 100644
--- a/services/java/com/android/server/DropBoxManagerService.java
+++ b/services/java/com/android/server/DropBoxManagerService.java
@@ -28,7 +28,6 @@
 import android.os.DropBoxManager;
 import android.os.FileUtils;
 import android.os.Handler;
-import android.os.ParcelFileDescriptor;
 import android.os.StatFs;
 import android.os.SystemClock;
 import android.provider.Settings;
@@ -45,14 +44,9 @@
 import java.io.InputStream;
 import java.io.InputStreamReader;
 import java.io.OutputStream;
-import java.io.OutputStreamWriter;
 import java.io.PrintWriter;
-import java.io.UnsupportedEncodingException;
 import java.util.ArrayList;
-import java.util.Comparator;
 import java.util.HashMap;
-import java.util.Iterator;
-import java.util.Map;
 import java.util.SortedSet;
 import java.util.TreeSet;
 import java.util.zip.GZIPOutputStream;
diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java
index 73d790a..6b64dd0 100644
--- a/services/java/com/android/server/InputMethodManagerService.java
+++ b/services/java/com/android/server/InputMethodManagerService.java
@@ -1,5 +1,4 @@
 /*
- * Copyright (C) 2006-2008 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
@@ -48,7 +47,6 @@
 import android.content.IntentFilter;
 import android.content.ServiceConnection;
 import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.ResolveInfo;
@@ -57,7 +55,6 @@
 import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.database.ContentObserver;
-import android.graphics.BitmapFactory;
 import android.inputmethodservice.InputMethodService;
 import android.os.Binder;
 import android.os.Environment;
@@ -98,12 +95,10 @@
 import java.io.IOException;
 import java.io.PrintWriter;
 import java.util.ArrayList;
-import java.util.Collections;
 import java.util.Comparator;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
-import java.util.Set;
 import java.util.TreeMap;
 
 /**
@@ -147,7 +142,6 @@
     final Handler mHandler;
     final InputMethodSettings mSettings;
     final SettingsObserver mSettingsObserver;
-    final StatusBarManagerService mStatusBar;
     final IWindowManager mIWindowManager;
     final HandlerCaller mCaller;
     private final InputMethodFileManager mFileManager;
@@ -162,10 +156,11 @@
             new LruCache<SuggestionSpan, InputMethodInfo>(SECURE_SUGGESTION_SPANS_MAX_SIZE);
 
     // Ongoing notification
-    private final NotificationManager mNotificationManager;
-    private final KeyguardManager mKeyguardManager;
-    private final Notification mImeSwitcherNotification;
-    private final PendingIntent mImeSwitchPendingIntent;
+    private NotificationManager mNotificationManager;
+    private KeyguardManager mKeyguardManager;
+    private StatusBarManagerService mStatusBar;
+    private Notification mImeSwitcherNotification;
+    private PendingIntent mImeSwitchPendingIntent;
     private boolean mShowOngoingImeSwitcherForPhones;
     private boolean mNotificationShown;
 
@@ -469,8 +464,7 @@
                             // Pick another one...
                             Slog.i(TAG, "Current input method removed: " + curInputMethodId);
                             mImeWindowVis = 0;
-                            mStatusBar.setImeWindowStatus(mCurToken, mImeWindowVis,
-                                    mBackDisposition);
+                            updateImeWindowStatusLocked();
                             if (!chooseNewDefaultIMELocked()) {
                                 changed = true;
                                 curIm = null;
@@ -511,7 +505,7 @@
         }
     }
 
-    public InputMethodManagerService(Context context, StatusBarManagerService statusBar) {
+    public InputMethodManagerService(Context context) {
         mContext = context;
         mRes = context.getResources();
         mHandler = new Handler(this);
@@ -524,10 +518,6 @@
             }
         });
 
-        mKeyguardManager = (KeyguardManager)
-                mContext.getSystemService(Context.KEYGUARD_SERVICE);
-        mNotificationManager = (NotificationManager)
-                mContext.getSystemService(Context.NOTIFICATION_SERVICE);
         mImeSwitcherNotification = new Notification();
         mImeSwitcherNotification.icon = com.android.internal.R.drawable.ic_notification_ime_default;
         mImeSwitcherNotification.when = 0;
@@ -553,8 +543,6 @@
         screenOnOffFilt.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
         mContext.registerReceiver(new ScreenOnOffReceiver(), screenOnOffFilt);
 
-        mStatusBar = statusBar;
-        statusBar.setIconVisibility("ime", false);
         mNotificationShown = false;
 
         // mSettings should be created before buildInputMethodListLocked
@@ -608,10 +596,17 @@
         }
     }
 
-    public void systemReady() {
+    public void systemReady(StatusBarManagerService statusBar) {
         synchronized (mMethodMap) {
             if (!mSystemReady) {
                 mSystemReady = true;
+                mKeyguardManager = (KeyguardManager)
+                        mContext.getSystemService(Context.KEYGUARD_SERVICE);
+                mNotificationManager = (NotificationManager)
+                        mContext.getSystemService(Context.NOTIFICATION_SERVICE);
+                mStatusBar = statusBar;
+                statusBar.setIconVisibility("ime", false);
+                updateImeWindowStatusLocked();
                 mShowOngoingImeSwitcherForPhones = mRes.getBoolean(
                         com.android.internal.R.bool.show_ongoing_ime_switcher);
                 try {
@@ -623,6 +618,13 @@
         }
     }
 
+    void updateImeWindowStatusLocked() {
+        if (mStatusBar != null) {
+            mStatusBar.setImeWindowStatus(mCurToken, mImeWindowVis,
+                    mBackDisposition);
+        }
+    }
+
     @Override
     public List<InputMethodInfo> getInputMethodList() {
         synchronized (mMethodMap) {
@@ -1009,7 +1011,9 @@
             mEnabledSession = null;
             mCurMethod = null;
         }
-        mStatusBar.setIconVisibility("ime", false);
+        if (mStatusBar != null) {
+            mStatusBar.setIconVisibility("ime", false);
+        }
     }
 
     @Override
@@ -1046,7 +1050,9 @@
             synchronized (mMethodMap) {
                 if (iconId == 0) {
                     if (DEBUG) Slog.d(TAG, "hide the small icon for the input method");
-                    mStatusBar.setIconVisibility("ime", false);
+                    if (mStatusBar != null) {
+                        mStatusBar.setIconVisibility("ime", false);
+                    }
                 } else if (packageName != null) {
                     if (DEBUG) Slog.d(TAG, "show a small icon for the input method");
                     CharSequence contentDescription = null;
@@ -1057,9 +1063,12 @@
                     } catch (NameNotFoundException nnfe) {
                         /* ignore */
                     }
-                    mStatusBar.setIcon("ime", packageName, iconId, 0,
-                            contentDescription  != null ? contentDescription.toString() : null);
-                    mStatusBar.setIconVisibility("ime", true);
+                    if (mStatusBar != null) {
+                        mStatusBar.setIcon("ime", packageName, iconId, 0,
+                                contentDescription  != null
+                                        ? contentDescription.toString() : null);
+                        mStatusBar.setIconVisibility("ime", true);
+                    }
                 }
             }
         } finally {
@@ -1125,7 +1134,9 @@
             synchronized (mMethodMap) {
                 mImeWindowVis = vis;
                 mBackDisposition = backDisposition;
-                mStatusBar.setImeWindowStatus(token, vis, backDisposition);
+                if (mStatusBar != null) {
+                    mStatusBar.setImeWindowStatus(token, vis, backDisposition);
+                }
                 final boolean iconVisibility = (vis & InputMethodService.IME_ACTIVE) != 0;
                 final InputMethodInfo imi = mMethodMap.get(mCurMethodId);
                 if (imi != null && iconVisibility && needsToShowImeSwitchOngoingNotification()) {
@@ -1142,12 +1153,14 @@
 
                     mImeSwitcherNotification.setLatestEventInfo(
                             mContext, title, summary, mImeSwitchPendingIntent);
-                    mNotificationManager.notify(
-                            com.android.internal.R.string.select_input_method,
-                            mImeSwitcherNotification);
-                    mNotificationShown = true;
+                    if (mNotificationManager != null) {
+                        mNotificationManager.notify(
+                                com.android.internal.R.string.select_input_method,
+                                mImeSwitcherNotification);
+                        mNotificationShown = true;
+                    }
                 } else {
-                    if (mNotificationShown) {
+                    if (mNotificationShown && mNotificationManager != null) {
                         mNotificationManager.cancel(
                                 com.android.internal.R.string.select_input_method);
                         mNotificationShown = false;
@@ -1252,8 +1265,7 @@
                             mImeWindowVis = (mInputShown || hardKeyShown) ? (
                                     InputMethodService.IME_ACTIVE | InputMethodService.IME_VISIBLE)
                                     : 0;
-                            mStatusBar.setImeWindowStatus(mCurToken, mImeWindowVis,
-                                    mBackDisposition);
+                            updateImeWindowStatusLocked();
                             // If subtype is null, try to find the most applicable one from
                             // getCurrentInputMethodSubtype.
                             if (subtype == null) {
@@ -1374,13 +1386,12 @@
                             if (DEBUG) Slog.w(TAG, "Ignoring hideSoftInput of uid "
                                     + uid + ": " + client);
                             mImeWindowVis = 0;
-                            mStatusBar.setImeWindowStatus(mCurToken, mImeWindowVis,
-                                    mBackDisposition);
+                            updateImeWindowStatusLocked();
                             return false;
                         }
                     } catch (RemoteException e) {
                         mImeWindowVis = 0;
-                        mStatusBar.setImeWindowStatus(mCurToken, mImeWindowVis, mBackDisposition);
+                        updateImeWindowStatusLocked();
                         return false;
                     }
                 }
@@ -2151,7 +2162,7 @@
                         }
                     });
 
-            if (showSubtypes && !(mKeyguardManager.isKeyguardLocked()
+            if (showSubtypes && mKeyguardManager != null && !(mKeyguardManager.isKeyguardLocked()
                     && mKeyguardManager.isKeyguardSecure())) {
                 mDialogBuilder.setPositiveButton(
                         com.android.internal.R.string.configure_input_methods,
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 5dd3c5b..e6f92a5 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -40,6 +40,7 @@
 import android.server.search.SearchManagerService;
 import android.util.DisplayMetrics;
 import android.util.EventLog;
+import android.util.Log;
 import android.util.Slog;
 import android.view.WindowManager;
 
@@ -66,6 +67,11 @@
 
     ContentResolver mContentResolver;
 
+    void reportWtf(String msg, Throwable e) {
+        Slog.w(TAG, "***********************************************");
+        Log.wtf(TAG, "BOOT FAILURE " + msg, e);
+    }
+
     @Override
     public void run() {
         EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_SYSTEM_RUN,
@@ -116,7 +122,6 @@
         WindowManagerService wm = null;
         BluetoothService bluetooth = null;
         BluetoothA2dpService bluetoothA2dp = null;
-        WiredAccessoryObserver wiredAccessory = null;
         DockObserver dock = null;
         UsbService usb = null;
         UiModeManagerService uiMode = null;
@@ -222,7 +227,8 @@
             }
 
         } catch (RuntimeException e) {
-            Slog.e("System", "Failure starting core service", e);
+            Slog.e("System", "******************************************");
+            Slog.e("System", "************ Failure starting core service", e);
         }
 
         DevicePolicyManagerService devicePolicy = null;
@@ -235,13 +241,52 @@
         CountryDetectorService countryDetector = null;
         TextServicesManagerService tsms = null;
 
+        // Bring up services needed for UI.
+        if (factoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
+            try {
+                Slog.i(TAG, "Input Method Service");
+                imm = new InputMethodManagerService(context);
+                ServiceManager.addService(Context.INPUT_METHOD_SERVICE, imm);
+            } catch (Throwable e) {
+                reportWtf("starting Input Manager Service", e);
+            }
+
+            try {
+                Slog.i(TAG, "Accessibility Manager");
+                ServiceManager.addService(Context.ACCESSIBILITY_SERVICE,
+                        new AccessibilityManagerService(context));
+            } catch (Throwable e) {
+                reportWtf("starting Accessibility Manager", e);
+            }
+        }
+
+        try {
+            wm.displayReady();
+        } catch (Throwable e) {
+            reportWtf("making display ready", e);
+        }
+ 
+        try {
+            pm.performBootDexOpt();
+        } catch (Throwable e) {
+            reportWtf("performing boot dexopt", e);
+        }
+
+        try {
+            ActivityManagerNative.getDefault().showBootMessage(
+                    context.getResources().getText(
+                            com.android.internal.R.string.android_upgrading_starting_apps),
+                            false);
+        } catch (RemoteException e) {
+        }
+
         if (factoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
             try {
                 Slog.i(TAG, "Device Policy");
                 devicePolicy = new DevicePolicyManagerService(context);
                 ServiceManager.addService(Context.DEVICE_POLICY_SERVICE, devicePolicy);
             } catch (Throwable e) {
-                Slog.e(TAG, "Failure starting DevicePolicyService", e);
+                reportWtf("starting DevicePolicyService", e);
             }
 
             try {
@@ -249,7 +294,7 @@
                 statusBar = new StatusBarManagerService(context, wm);
                 ServiceManager.addService(Context.STATUS_BAR_SERVICE, statusBar);
             } catch (Throwable e) {
-                Slog.e(TAG, "Failure starting StatusBarManagerService", e);
+                reportWtf("starting StatusBarManagerService", e);
             }
 
             try {
@@ -257,15 +302,7 @@
                 ServiceManager.addService(Context.CLIPBOARD_SERVICE,
                         new ClipboardService(context));
             } catch (Throwable e) {
-                Slog.e(TAG, "Failure starting Clipboard Service", e);
-            }
-
-            try {
-                Slog.i(TAG, "Input Method Service");
-                imm = new InputMethodManagerService(context, statusBar);
-                ServiceManager.addService(Context.INPUT_METHOD_SERVICE, imm);
-            } catch (Throwable e) {
-                Slog.e(TAG, "Failure starting Input Manager Service", e);
+                reportWtf("starting Clipboard Service", e);
             }
 
             try {
@@ -273,7 +310,7 @@
                 networkManagement = NetworkManagementService.create(context);
                 ServiceManager.addService(Context.NETWORKMANAGEMENT_SERVICE, networkManagement);
             } catch (Throwable e) {
-                Slog.e(TAG, "Failure starting NetworkManagement Service", e);
+                reportWtf("starting NetworkManagement Service", e);
             }
 
             try {
@@ -281,7 +318,7 @@
                 tsms = new TextServicesManagerService(context);
                 ServiceManager.addService(Context.TEXT_SERVICES_MANAGER_SERVICE, tsms);
             } catch (Throwable e) {
-                Slog.e(TAG, "Failure starting Text Service Manager Service", e);
+                reportWtf("starting Text Service Manager Service", e);
             }
 
             try {
@@ -289,7 +326,7 @@
                 networkStats = new NetworkStatsService(context, networkManagement, alarm);
                 ServiceManager.addService(Context.NETWORK_STATS_SERVICE, networkStats);
             } catch (Throwable e) {
-                Slog.e(TAG, "Failure starting NetworkStats Service", e);
+                reportWtf("starting NetworkStats Service", e);
             }
 
             try {
@@ -299,7 +336,7 @@
                         networkStats, networkManagement);
                 ServiceManager.addService(Context.NETWORK_POLICY_SERVICE, networkPolicy);
             } catch (Throwable e) {
-                Slog.e(TAG, "Failure starting NetworkPolicy Service", e);
+                reportWtf("starting NetworkPolicy Service", e);
             }
 
            try {
@@ -307,7 +344,7 @@
                 wifiP2p = new WifiP2pService(context);
                 ServiceManager.addService(Context.WIFI_P2P_SERVICE, wifiP2p);
             } catch (Throwable e) {
-                Slog.e(TAG, "Failure starting Wi-Fi P2pService", e);
+                reportWtf("starting Wi-Fi P2pService", e);
             }
 
            try {
@@ -316,7 +353,7 @@
                 ServiceManager.addService(Context.WIFI_SERVICE, wifi);
                 wifi.checkAndStartWifi();
             } catch (Throwable e) {
-                Slog.e(TAG, "Failure starting Wi-Fi Service", e);
+                reportWtf("starting Wi-Fi Service", e);
             }
 
             try {
@@ -327,7 +364,7 @@
                 networkPolicy.bindConnectivityManager(connectivity);
                 wifiP2p.connectivityServiceReady();
             } catch (Throwable e) {
-                Slog.e(TAG, "Failure starting Connectivity Service", e);
+                reportWtf("starting Connectivity Service", e);
             }
 
             try {
@@ -336,15 +373,7 @@
                 ServiceManager.addService(
                         Context.THROTTLE_SERVICE, throttle);
             } catch (Throwable e) {
-                Slog.e(TAG, "Failure starting ThrottleService", e);
-            }
-
-            try {
-              Slog.i(TAG, "Accessibility Manager");
-              ServiceManager.addService(Context.ACCESSIBILITY_SERVICE,
-                      new AccessibilityManagerService(context));
-            } catch (Throwable e) {
-              Slog.e(TAG, "Failure starting Accessibility Manager", e);
+                reportWtf("starting ThrottleService", e);
             }
 
             try {
@@ -355,7 +384,7 @@
                 Slog.i(TAG, "Mount Service");
                 ServiceManager.addService("mount", new MountService(context));
             } catch (Throwable e) {
-                Slog.e(TAG, "Failure starting Mount Service", e);
+                reportWtf("starting Mount Service", e);
             }
 
             try {
@@ -364,7 +393,7 @@
                 ServiceManager.addService(Context.NOTIFICATION_SERVICE, notification);
                 networkPolicy.bindNotificationManager(notification);
             } catch (Throwable e) {
-                Slog.e(TAG, "Failure starting Notification Manager", e);
+                reportWtf("starting Notification Manager", e);
             }
 
             try {
@@ -372,7 +401,7 @@
                 ServiceManager.addService(DeviceStorageMonitorService.SERVICE,
                         new DeviceStorageMonitorService(context));
             } catch (Throwable e) {
-                Slog.e(TAG, "Failure starting DeviceStorageMonitor service", e);
+                reportWtf("starting DeviceStorageMonitor service", e);
             }
 
             try {
@@ -380,7 +409,7 @@
                 location = new LocationManagerService(context);
                 ServiceManager.addService(Context.LOCATION_SERVICE, location);
             } catch (Throwable e) {
-                Slog.e(TAG, "Failure starting Location Manager", e);
+                reportWtf("starting Location Manager", e);
             }
 
             try {
@@ -388,7 +417,7 @@
                 countryDetector = new CountryDetectorService(context);
                 ServiceManager.addService(Context.COUNTRY_DETECTOR, countryDetector);
             } catch (Throwable e) {
-                Slog.e(TAG, "Failure starting Country Detector", e);
+                reportWtf("starting Country Detector", e);
             }
 
             try {
@@ -396,7 +425,7 @@
                 ServiceManager.addService(Context.SEARCH_SERVICE,
                         new SearchManagerService(context));
             } catch (Throwable e) {
-                Slog.e(TAG, "Failure starting Search Service", e);
+                reportWtf("starting Search Service", e);
             }
 
             try {
@@ -404,7 +433,7 @@
                 ServiceManager.addService(Context.DROPBOX_SERVICE,
                         new DropBoxManagerService(context, new File("/data/system/dropbox")));
             } catch (Throwable e) {
-                Slog.e(TAG, "Failure starting DropBoxManagerService", e);
+                reportWtf("starting DropBoxManagerService", e);
             }
 
             try {
@@ -412,14 +441,14 @@
                 wallpaper = new WallpaperManagerService(context);
                 ServiceManager.addService(Context.WALLPAPER_SERVICE, wallpaper);
             } catch (Throwable e) {
-                Slog.e(TAG, "Failure starting Wallpaper Service", e);
+                reportWtf("starting Wallpaper Service", e);
             }
 
             try {
                 Slog.i(TAG, "Audio Service");
                 ServiceManager.addService(Context.AUDIO_SERVICE, new AudioService(context));
             } catch (Throwable e) {
-                Slog.e(TAG, "Failure starting Audio Service", e);
+                reportWtf("starting Audio Service", e);
             }
 
             try {
@@ -427,15 +456,15 @@
                 // Listen for dock station changes
                 dock = new DockObserver(context, power);
             } catch (Throwable e) {
-                Slog.e(TAG, "Failure starting DockObserver", e);
+                reportWtf("starting DockObserver", e);
             }
 
             try {
                 Slog.i(TAG, "Wired Accessory Observer");
                 // Listen for wired headset changes
-                wiredAccessory = new WiredAccessoryObserver(context);
+                new WiredAccessoryObserver(context);
             } catch (Throwable e) {
-                Slog.e(TAG, "Failure starting WiredAccessoryObserver", e);
+                reportWtf("starting WiredAccessoryObserver", e);
             }
 
             try {
@@ -444,7 +473,7 @@
                 usb = new UsbService(context);
                 ServiceManager.addService(Context.USB_SERVICE, usb);
             } catch (Throwable e) {
-                Slog.e(TAG, "Failure starting UsbService", e);
+                reportWtf("starting UsbService", e);
             }
 
             try {
@@ -452,7 +481,7 @@
                 // Listen for UI mode changes
                 uiMode = new UiModeManagerService(context);
             } catch (Throwable e) {
-                Slog.e(TAG, "Failure starting UiModeManagerService", e);
+                reportWtf("starting UiModeManagerService", e);
             }
 
             try {
@@ -468,21 +497,21 @@
                 appWidget = new AppWidgetService(context);
                 ServiceManager.addService(Context.APPWIDGET_SERVICE, appWidget);
             } catch (Throwable e) {
-                Slog.e(TAG, "Failure starting AppWidget Service", e);
+                reportWtf("starting AppWidget Service", e);
             }
 
             try {
                 Slog.i(TAG, "Recognition Service");
                 recognition = new RecognitionManagerService(context);
             } catch (Throwable e) {
-                Slog.e(TAG, "Failure starting Recognition Service", e);
+                reportWtf("starting Recognition Service", e);
             }
 
             try {
                 Slog.i(TAG, "DiskStats Service");
                 ServiceManager.addService("diskstats", new DiskStatsService(context));
             } catch (Throwable e) {
-                Slog.e(TAG, "Failure starting DiskStats Service", e);
+                reportWtf("starting DiskStats Service", e);
             }
 
             try {
@@ -494,14 +523,14 @@
                 ServiceManager.addService("samplingprofiler",
                             new SamplingProfilerService(context));
             } catch (Throwable e) {
-                Slog.e(TAG, "Failure starting SamplingProfiler Service", e);
+                reportWtf("starting SamplingProfiler Service", e);
             }
 
             try {
                 Slog.i(TAG, "NetworkTimeUpdateService");
                 networkTimeUpdater = new NetworkTimeUpdateService(context);
             } catch (Throwable e) {
-                Slog.e(TAG, "Failure starting NetworkTimeUpdate service");
+                reportWtf("starting NetworkTimeUpdate service", e);
             }
         }
 
@@ -522,14 +551,26 @@
         // It is now time to start up the app processes...
 
         if (devicePolicy != null) {
-            devicePolicy.systemReady();
+            try {
+                devicePolicy.systemReady();
+            } catch (Throwable e) {
+                reportWtf("making Device Policy Service ready", e);
+            }
         }
 
         if (notification != null) {
-            notification.systemReady();
+            try {
+                notification.systemReady();
+            } catch (Throwable e) {
+                reportWtf("making Notification Service ready", e);
+            }
         }
 
-        wm.systemReady();
+        try {
+            wm.systemReady();
+        } catch (Throwable e) {
+            reportWtf("making Window Manager Service ready", e);
+        }
 
         if (safeMode) {
             ActivityManagerService.self().showSafeModeOverlay();
@@ -547,7 +588,8 @@
         power.systemReady();
         try {
             pm.systemReady();
-        } catch (RemoteException e) {
+        } catch (Throwable e) {
+            reportWtf("making Package Manager Service ready", e);
         }
 
         // These are needed to propagate to the runnable below.
@@ -569,6 +611,7 @@
         final CountryDetectorService countryDetectorF = countryDetector;
         final NetworkTimeUpdateService networkTimeUpdaterF = networkTimeUpdater;
         final TextServicesManagerService textServiceManagerServiceF = tsms;
+        final StatusBarManagerService statusBarF = statusBar;
 
         // We now tell the activity manager it is okay to run third party
         // code.  It will call back into us once it has gotten to the state
@@ -581,28 +624,96 @@
                 Slog.i(TAG, "Making services ready");
 
                 startSystemUi(contextF);
-                if (batteryF != null) batteryF.systemReady();
-                if (networkManagementF != null) networkManagementF.systemReady();
-                if (networkStatsF != null) networkStatsF.systemReady();
-                if (networkPolicyF != null) networkPolicyF.systemReady();
-                if (connectivityF != null) connectivityF.systemReady();
-                if (dockF != null) dockF.systemReady();
-                if (usbF != null) usbF.systemReady();
-                if (uiModeF != null) uiModeF.systemReady();
-                if (recognitionF != null) recognitionF.systemReady();
+                try {
+                    if (batteryF != null) batteryF.systemReady();
+                } catch (Throwable e) {
+                    reportWtf("making Battery Service ready", e);
+                }
+                try {
+                    if (networkManagementF != null) networkManagementF.systemReady();
+                } catch (Throwable e) {
+                    reportWtf("making Network Managment Service ready", e);
+                }
+                try {
+                    if (networkStatsF != null) networkStatsF.systemReady();
+                } catch (Throwable e) {
+                    reportWtf("making Network Stats Service ready", e);
+                }
+                try {
+                    if (networkPolicyF != null) networkPolicyF.systemReady();
+                } catch (Throwable e) {
+                    reportWtf("making Network Policy Service ready", e);
+                }
+                try {
+                    if (connectivityF != null) connectivityF.systemReady();
+                } catch (Throwable e) {
+                    reportWtf("making Connectivity Service ready", e);
+                }
+                try {
+                    if (dockF != null) dockF.systemReady();
+                } catch (Throwable e) {
+                    reportWtf("making Dock Service ready", e);
+                }
+                try {
+                    if (usbF != null) usbF.systemReady();
+                } catch (Throwable e) {
+                    reportWtf("making USB Service ready", e);
+                }
+                try {
+                    if (uiModeF != null) uiModeF.systemReady();
+                } catch (Throwable e) {
+                    reportWtf("making UI Mode Service ready", e);
+                }
+                try {
+                    if (recognitionF != null) recognitionF.systemReady();
+                } catch (Throwable e) {
+                    reportWtf("making Recognition Service ready", e);
+                }
                 Watchdog.getInstance().start();
 
                 // It is now okay to let the various system services start their
                 // third party code...
 
-                if (appWidgetF != null) appWidgetF.systemReady(safeMode);
-                if (wallpaperF != null) wallpaperF.systemReady();
-                if (immF != null) immF.systemReady();
-                if (locationF != null) locationF.systemReady();
-                if (countryDetectorF != null) countryDetectorF.systemReady();
-                if (throttleF != null) throttleF.systemReady();
-                if (networkTimeUpdaterF != null) networkTimeUpdaterF.systemReady();
-                if (textServiceManagerServiceF != null) textServiceManagerServiceF.systemReady();
+                try {
+                    if (appWidgetF != null) appWidgetF.systemReady(safeMode);
+                } catch (Throwable e) {
+                    reportWtf("making App Widget Service ready", e);
+                }
+                try {
+                    if (wallpaperF != null) wallpaperF.systemReady();
+                } catch (Throwable e) {
+                    reportWtf("making Wallpaper Service ready", e);
+                }
+                try {
+                    if (immF != null) immF.systemReady(statusBarF);
+                } catch (Throwable e) {
+                    reportWtf("making Input Method Service ready", e);
+                }
+                try {
+                    if (locationF != null) locationF.systemReady();
+                } catch (Throwable e) {
+                    reportWtf("making Location Service ready", e);
+                }
+                try {
+                    if (countryDetectorF != null) countryDetectorF.systemReady();
+                } catch (Throwable e) {
+                    reportWtf("making Country Detector Service ready", e);
+                }
+                try {
+                    if (throttleF != null) throttleF.systemReady();
+                } catch (Throwable e) {
+                    reportWtf("making Throttle Service ready", e);
+                }
+                try {
+                    if (networkTimeUpdaterF != null) networkTimeUpdaterF.systemReady();
+                } catch (Throwable e) {
+                    reportWtf("making Network Time Service ready", e);
+                }
+                try {
+                    if (textServiceManagerServiceF != null) textServiceManagerServiceF.systemReady();
+                } catch (Throwable e) {
+                    reportWtf("making Text Services Manager Service ready", e);
+                }
             }
         });
 
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 800c4fc..b817598 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -91,6 +91,7 @@
 import android.os.FileObserver;
 import android.os.FileUtils;
 import android.os.Handler;
+import android.os.HandlerThread;
 import android.os.IBinder;
 import android.os.IPermissionController;
 import android.os.Looper;
@@ -3748,6 +3749,10 @@
         mWindowManager.enableScreenAfterBoot();
     }
 
+    public void showBootMessage(final CharSequence msg, final boolean always) {
+        mWindowManager.showBootMessage(msg, always);
+    }
+
     final void finishBooting() {
         IntentFilter pkgFilter = new IntentFilter();
         pkgFilter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
@@ -6446,7 +6451,9 @@
         File fname = new File(systemDir, "called_pre_boots.dat");
         return fname;
     }
-    
+
+    static final int LAST_DONE_VERSION = 10000;
+
     private static ArrayList<ComponentName> readLastDonePreBootReceivers() {
         ArrayList<ComponentName> lastDoneReceivers = new ArrayList<ComponentName>();
         File file = getCalledPreBootReceiversFile();
@@ -6454,16 +6461,21 @@
         try {
             fis = new FileInputStream(file);
             DataInputStream dis = new DataInputStream(new BufferedInputStream(fis, 2048));
-            int vers = dis.readInt();
-            String codename = dis.readUTF();
-            if (vers == android.os.Build.VERSION.SDK_INT
-                    && codename.equals(android.os.Build.VERSION.CODENAME)) {
-                int num = dis.readInt();
-                while (num > 0) {
-                    num--;
-                    String pkg = dis.readUTF();
-                    String cls = dis.readUTF();
-                    lastDoneReceivers.add(new ComponentName(pkg, cls));
+            int fvers = dis.readInt();
+            if (fvers == LAST_DONE_VERSION) {
+                String vers = dis.readUTF();
+                String codename = dis.readUTF();
+                String build = dis.readUTF();
+                if (android.os.Build.VERSION.RELEASE.equals(vers)
+                        && android.os.Build.VERSION.CODENAME.equals(codename)
+                        && android.os.Build.VERSION.INCREMENTAL.equals(build)) {
+                    int num = dis.readInt();
+                    while (num > 0) {
+                        num--;
+                        String pkg = dis.readUTF();
+                        String cls = dis.readUTF();
+                        lastDoneReceivers.add(new ComponentName(pkg, cls));
+                    }
                 }
             }
         } catch (FileNotFoundException e) {
@@ -6488,8 +6500,10 @@
             Slog.i(TAG, "Writing new set of last done pre-boot receivers...");
             fos = new FileOutputStream(file);
             dos = new DataOutputStream(new BufferedOutputStream(fos, 2048));
-            dos.writeInt(android.os.Build.VERSION.SDK_INT);
+            dos.writeInt(LAST_DONE_VERSION);
+            dos.writeUTF(android.os.Build.VERSION.RELEASE);
             dos.writeUTF(android.os.Build.VERSION.CODENAME);
+            dos.writeUTF(android.os.Build.VERSION.INCREMENTAL);
             dos.writeInt(list.size());
             for (int i=0; i<list.size(); i++) {
                 dos.writeUTF(list.get(i).getPackageName());
@@ -6571,6 +6585,9 @@
                                                 mDidUpdate = true;
                                             }
                                             writeLastDonePreBootReceivers(doneReceivers);
+                                            showBootMessage(mContext.getText(
+                                                    R.string.android_upgrading_complete),
+                                                    false);
                                             systemReady(goingCallback);
                                         }
                                     });
diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java
index dbb8164..2f19a46 100644
--- a/services/java/com/android/server/pm/PackageManagerService.java
+++ b/services/java/com/android/server/pm/PackageManagerService.java
@@ -187,6 +187,7 @@
     static final int SCAN_NEW_INSTALL = 1<<4;
     static final int SCAN_NO_PATHS = 1<<5;
     static final int SCAN_UPDATE_TIME = 1<<6;
+    static final int SCAN_DEFER_DEX = 1<<7;
 
     static final int REMOVE_CHATTY = 1<<16;
 
@@ -349,6 +350,9 @@
     /** List of packages waiting for verification. */
     final SparseArray<InstallArgs> mPendingVerification = new SparseArray<InstallArgs>();
 
+    final ArrayList<PackageParser.Package> mDeferredDexOpt =
+            new ArrayList<PackageParser.Package>();
+
     /** Token for keys in mPendingVerification. */
     private int mPendingVerificationToken = 0;
 
@@ -907,7 +911,7 @@
 
             // Set flag to monitor and not change apk file paths when
             // scanning install directories.
-            int scanMode = SCAN_MONITOR | SCAN_NO_PATHS;
+            int scanMode = SCAN_MONITOR | SCAN_NO_PATHS | SCAN_DEFER_DEX;
             if (mNoDexOpt) {
                 Slog.w(TAG, "Running ENG build: no pre-dexopt!");
                 scanMode |= SCAN_NO_DEX;
@@ -2899,6 +2903,33 @@
         }
     }
 
+    public void performBootDexOpt() {
+        ArrayList<PackageParser.Package> pkgs = null;
+        synchronized (mPackages) {
+            if (mDeferredDexOpt.size() > 0) {
+                pkgs = new ArrayList<PackageParser.Package>(mDeferredDexOpt);
+                mDeferredDexOpt.clear();
+            }
+        }
+        if (pkgs != null) {
+            for (int i=0; i<pkgs.size(); i++) {
+                try {
+                    ActivityManagerNative.getDefault().showBootMessage(
+                            mContext.getResources().getString(
+                                    com.android.internal.R.string.android_upgrading_apk,
+                                    i+1, pkgs.size()), true);
+                } catch (RemoteException e) {
+                }
+                PackageParser.Package p = pkgs.get(i);
+                synchronized (mInstallLock) {
+                    if (!p.mDidDexOpt) {
+                        performDexOptLI(p, false, false);
+                    }
+                }
+            }
+        }
+    }
+
     public boolean performDexOpt(String packageName) {
         enforceSystemOrRoot("Only the system can request dexopt be performed");
 
@@ -2914,25 +2945,32 @@
             }
         }
         synchronized (mInstallLock) {
-            return performDexOptLI(p, false) == DEX_OPT_PERFORMED;
+            return performDexOptLI(p, false, false) == DEX_OPT_PERFORMED;
         }
     }
 
     static final int DEX_OPT_SKIPPED = 0;
     static final int DEX_OPT_PERFORMED = 1;
+    static final int DEX_OPT_DEFERRED = 2;
     static final int DEX_OPT_FAILED = -1;
 
-    private int performDexOptLI(PackageParser.Package pkg, boolean forceDex) {
+    private int performDexOptLI(PackageParser.Package pkg, boolean forceDex, boolean defer) {
         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,
-                            !isForwardLocked(pkg));
-                    pkg.mDidDexOpt = true;
-                    performed = true;
+                    if (!forceDex && defer) {
+                        mDeferredDexOpt.add(pkg);
+                        return DEX_OPT_DEFERRED;
+                    } else {
+                        Log.i(TAG, "Running dexopt on: " + pkg.applicationInfo.packageName);
+                        ret = mInstaller.dexopt(path, pkg.applicationInfo.uid,
+                                !isForwardLocked(pkg));
+                        pkg.mDidDexOpt = true;
+                        performed = true;
+                    }
                 }
             } catch (FileNotFoundException e) {
                 Slog.w(TAG, "Apk not found for dexopt: " + path);
@@ -3487,7 +3525,8 @@
         pkg.mScanPath = path;
 
         if ((scanMode&SCAN_NO_DEX) == 0) {
-            if (performDexOptLI(pkg, forceDex) == DEX_OPT_FAILED) {
+            if (performDexOptLI(pkg, forceDex, (scanMode&SCAN_DEFER_DEX) != 0)
+                    == DEX_OPT_FAILED) {
                 mLastScanError = PackageManager.INSTALL_FAILED_DEXOPT;
                 return null;
             }
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index 8fd4f95..dc5555e 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -50,6 +50,7 @@
 import android.Manifest;
 import android.app.ActivityManagerNative;
 import android.app.IActivityManager;
+import android.app.ProgressDialog;
 import android.app.StatusBarManager;
 import android.app.admin.DevicePolicyManager;
 import android.content.BroadcastReceiver;
@@ -407,6 +408,7 @@
     boolean mSafeMode;
     boolean mDisplayEnabled = false;
     boolean mSystemBooted = false;
+    boolean mShowingBootMessages = false;
     int mInitialDisplayWidth = 0;
     int mInitialDisplayHeight = 0;
     int mBaseDisplayWidth = 0;
@@ -4685,16 +4687,17 @@
                 return;
             }
             mSystemBooted = true;
+            hideBootMessagesLocked();
         }
 
         performEnableScreen();
     }
 
-    public void enableScreenIfNeededLocked() {
+    void enableScreenIfNeededLocked() {
         if (mDisplayEnabled) {
             return;
         }
-        if (!mSystemBooted) {
+        if (!mSystemBooted && !mShowingBootMessages) {
             return;
         }
         mH.sendMessage(mH.obtainMessage(H.ENABLE_SCREEN));
@@ -4705,7 +4708,7 @@
             if (mDisplayEnabled) {
                 return;
             }
-            if (!mSystemBooted) {
+            if (!mSystemBooted && !mShowingBootMessages) {
                 return;
             }
 
@@ -4749,6 +4752,33 @@
                 mLastRotationFlags | Surface.FLAGS_ORIENTATION_ANIMATION_DISABLE);
     }
 
+    public void showBootMessage(final CharSequence msg, final boolean always) {
+        boolean first = false;
+        synchronized(mWindowMap) {
+            if (!mShowingBootMessages) {
+                if (!always) {
+                    return;
+                }
+                first = true;
+            }
+            if (mSystemBooted) {
+                return;
+            }
+            mShowingBootMessages = true;
+            mPolicy.showBootMessage(msg, always);
+        }
+        if (first) {
+            performEnableScreen();
+        }
+    }
+
+    public void hideBootMessagesLocked() {
+        if (mShowingBootMessages) {
+            mShowingBootMessages = false;
+            mPolicy.hideBootMessages();
+        }
+    }
+
     public void setInTouchMode(boolean mode) {
         synchronized(mWindowMap) {
             mInTouchMode = mode;
@@ -6136,7 +6166,7 @@
         return mSafeMode;
     }
 
-    public void systemReady() {
+    public void displayReady() {
         synchronized(mWindowMap) {
             if (mDisplay != null) {
                 throw new IllegalStateException("Display already initialized");
@@ -6165,14 +6195,16 @@
             mActivityManager.updateConfiguration(null);
         } catch (RemoteException e) {
         }
-
-        mPolicy.systemReady();
-
+        
         synchronized (mWindowMap) {
             readForcedDisplaySizeLocked();
         }
     }
 
+    public void systemReady() {
+        mPolicy.systemReady();
+    }
+
     // This is an animation that does nothing: it just immediately finishes
     // itself every time it is called.  It is used as a stub animation in cases
     // where we want to synchronize multiple things that may be animating.