Move handling of package changes to a background thread.

Helps get rid of some jank when installing applications.

Change-Id: I97d0022f82d67796e334d37086e5911dd6ca6b62
diff --git a/core/java/android/server/search/SearchManagerService.java b/core/java/android/server/search/SearchManagerService.java
index d78bbbf..c783e6a 100644
--- a/core/java/android/server/search/SearchManagerService.java
+++ b/core/java/android/server/search/SearchManagerService.java
@@ -69,7 +69,7 @@
     private synchronized Searchables getSearchables() {
         if (mSearchables == null) {
             Log.i(TAG, "Building list of searchable activities");
-            new MyPackageMonitor().register(mContext, true);
+            new MyPackageMonitor().register(mContext, null, true);
             mSearchables = new Searchables(mContext);
             mSearchables.buildSearchableList();
         }
diff --git a/core/java/android/widget/ActivityChooserModel.java b/core/java/android/widget/ActivityChooserModel.java
index bc44521..c53b5f6 100644
--- a/core/java/android/widget/ActivityChooserModel.java
+++ b/core/java/android/widget/ActivityChooserModel.java
@@ -365,7 +365,7 @@
         } else {
             mHistoryFileName = historyFileName;
         }
-        mPackageMonitor.register(mContext, true);
+        mPackageMonitor.register(mContext, null, true);
     }
 
     /**
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index af722a8..5862d3e 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -99,7 +99,7 @@
         ap.mTitle = title;
         ap.mOnClickListener = this;
 
-        mPackageMonitor.register(this, false);
+        mPackageMonitor.register(this, getMainLooper(), false);
 
         if (alwaysUseOption) {
             LayoutInflater inflater = (LayoutInflater) getSystemService(
@@ -135,7 +135,7 @@
     @Override
     protected void onRestart() {
         super.onRestart();
-        mPackageMonitor.register(this, false);
+        mPackageMonitor.register(this, getMainLooper(), false);
         mAdapter.handlePackagesChanged();
     }
 
diff --git a/core/java/com/android/internal/content/PackageMonitor.java b/core/java/com/android/internal/content/PackageMonitor.java
index 32d86413..f41fcc6 100644
--- a/core/java/com/android/internal/content/PackageMonitor.java
+++ b/core/java/com/android/internal/content/PackageMonitor.java
@@ -21,6 +21,9 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.net.Uri;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Looper;
 
 import java.util.HashSet;
 
@@ -32,7 +35,11 @@
     static final IntentFilter sPackageFilt = new IntentFilter();
     static final IntentFilter sNonDataFilt = new IntentFilter();
     static final IntentFilter sExternalFilt = new IntentFilter();
-    
+
+    static final Object sLock = new Object();
+    static HandlerThread sBackgroundThread;
+    static Handler sBackgroundHandler;
+
     static {
         sPackageFilt.addAction(Intent.ACTION_PACKAGE_ADDED);
         sPackageFilt.addAction(Intent.ACTION_PACKAGE_REMOVED);
@@ -49,6 +56,7 @@
     final HashSet<String> mUpdatingPackages = new HashSet<String>();
     
     Context mRegisteredContext;
+    Handler mRegisteredHandler;
     String[] mDisappearingPackages;
     String[] mAppearingPackages;
     String[] mModifiedPackages;
@@ -57,18 +65,35 @@
     
     String[] mTempArray = new String[1];
     
-    public void register(Context context, boolean externalStorage) {
+    public void register(Context context, Looper thread, boolean externalStorage) {
         if (mRegisteredContext != null) {
             throw new IllegalStateException("Already registered");
         }
         mRegisteredContext = context;
-        context.registerReceiver(this, sPackageFilt);
-        context.registerReceiver(this, sNonDataFilt);
+        if (thread == null) {
+            synchronized (sLock) {
+                if (sBackgroundThread == null) {
+                    sBackgroundThread = new HandlerThread("PackageMonitor",
+                            android.os.Process.THREAD_PRIORITY_BACKGROUND);
+                    sBackgroundThread.start();
+                    sBackgroundHandler = new Handler(sBackgroundThread.getLooper());
+                }
+                mRegisteredHandler = sBackgroundHandler;
+            }
+        } else {
+            mRegisteredHandler = new Handler(thread);
+        }
+        context.registerReceiver(this, sPackageFilt, null, mRegisteredHandler);
+        context.registerReceiver(this, sNonDataFilt, null, mRegisteredHandler);
         if (externalStorage) {
-            context.registerReceiver(this, sExternalFilt);
+            context.registerReceiver(this, sExternalFilt, null, mRegisteredHandler);
         }
     }
-    
+
+    public Handler getRegisteredHandler() {
+        return mRegisteredHandler;
+    }
+
     public void unregister() {
         if (mRegisteredContext == null) {
             throw new IllegalStateException("Not registered");
diff --git a/services/java/com/android/server/DevicePolicyManagerService.java b/services/java/com/android/server/DevicePolicyManagerService.java
index d8e3d59..eb33060 100644
--- a/services/java/com/android/server/DevicePolicyManagerService.java
+++ b/services/java/com/android/server/DevicePolicyManagerService.java
@@ -451,7 +451,7 @@
     public DevicePolicyManagerService(Context context) {
         mContext = context;
         mMonitor = new MyPackageMonitor();
-        mMonitor.register(context, true);
+        mMonitor.register(context, null, true);
         mWakeLock = ((PowerManager)context.getSystemService(Context.POWER_SERVICE))
                 .newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "DPM");
         IntentFilter filter = new IntentFilter();
diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java
index a474cec..43c2292 100644
--- a/services/java/com/android/server/InputMethodManagerService.java
+++ b/services/java/com/android/server/InputMethodManagerService.java
@@ -594,7 +594,7 @@
         }
         mImListManager = new InputMethodAndSubtypeListManager(context, this);
 
-        (new MyPackageMonitor()).register(mContext, true);
+        (new MyPackageMonitor()).register(mContext, null, true);
 
         IntentFilter screenOnOffFilt = new IntentFilter();
         screenOnOffFilt.addAction(Intent.ACTION_SCREEN_ON);
diff --git a/services/java/com/android/server/LocationManagerService.java b/services/java/com/android/server/LocationManagerService.java
index 8cb9d99b..d651111 100644
--- a/services/java/com/android/server/LocationManagerService.java
+++ b/services/java/com/android/server/LocationManagerService.java
@@ -511,7 +511,7 @@
                 com.android.internal.R.string.config_networkLocationProvider);
         mGeocodeProviderPackageName = resources.getString(
                 com.android.internal.R.string.config_geocodeProvider);
-        mPackageMonitor.register(context, true);
+        mPackageMonitor.register(context, null, true);
 
         if (LOCAL_LOGV) {
             Slog.v(TAG, "Constructed LocationManager Service");
diff --git a/services/java/com/android/server/RecognitionManagerService.java b/services/java/com/android/server/RecognitionManagerService.java
index 85224d8..3567cfc 100644
--- a/services/java/com/android/server/RecognitionManagerService.java
+++ b/services/java/com/android/server/RecognitionManagerService.java
@@ -65,7 +65,7 @@
     RecognitionManagerService(Context context) {
         mContext = context;
         mMonitor = new MyPackageMonitor();
-        mMonitor.register(context, true);
+        mMonitor.register(context, null, true);
     }
     
     public void systemReady() {
diff --git a/services/java/com/android/server/TextServicesManagerService.java b/services/java/com/android/server/TextServicesManagerService.java
index 106bb3e..499ff7a 100644
--- a/services/java/com/android/server/TextServicesManagerService.java
+++ b/services/java/com/android/server/TextServicesManagerService.java
@@ -77,7 +77,7 @@
         mSystemReady = false;
         mContext = context;
         mMonitor = new TextServicesMonitor();
-        mMonitor.register(context, true);
+        mMonitor.register(context, null, true);
         synchronized (mSpellCheckerMap) {
             buildSpellCheckerMapLocked(context, mSpellCheckerList, mSpellCheckerMap);
         }
diff --git a/services/java/com/android/server/WallpaperManagerService.java b/services/java/com/android/server/WallpaperManagerService.java
index 6d83f30..d97d335 100644
--- a/services/java/com/android/server/WallpaperManagerService.java
+++ b/services/java/com/android/server/WallpaperManagerService.java
@@ -295,7 +295,7 @@
                             || !wallpaper.wallpaperComponent.getPackageName().equals(packageName)) {
                         continue;
                     }
-                    doPackagesChanged(true, wallpaper);
+                    doPackagesChangedLocked(true, wallpaper);
                 }
             }
         }
@@ -315,66 +315,68 @@
 
         @Override
         public boolean onHandleForceStop(Intent intent, String[] packages, int uid, boolean doit) {
-            boolean changed = false;
-            for (int i = 0; i < mWallpaperMap.size(); i++) {
-                WallpaperData wallpaper = mWallpaperMap.valueAt(i);
-                boolean res = doPackagesChanged(doit, wallpaper);
-                changed |= res;
+            synchronized (mLock) {
+                boolean changed = false;
+                for (int i = 0; i < mWallpaperMap.size(); i++) {
+                    WallpaperData wallpaper = mWallpaperMap.valueAt(i);
+                    boolean res = doPackagesChangedLocked(doit, wallpaper);
+                    changed |= res;
+                }
+                return changed;
             }
-            return changed;
         }
 
         @Override
         public void onSomePackagesChanged() {
-            for (int i = 0; i < mWallpaperMap.size(); i++) {
-                WallpaperData wallpaper = mWallpaperMap.valueAt(i);
-                doPackagesChanged(true, wallpaper);
+            synchronized (mLock) {
+                for (int i = 0; i < mWallpaperMap.size(); i++) {
+                    WallpaperData wallpaper = mWallpaperMap.valueAt(i);
+                    doPackagesChangedLocked(true, wallpaper);
+                }
             }
         }
 
-        boolean doPackagesChanged(boolean doit, WallpaperData wallpaper) {
+        boolean doPackagesChangedLocked(boolean doit, WallpaperData wallpaper) {
             boolean changed = false;
-            synchronized (mLock) {
-                if (wallpaper.wallpaperComponent != null) {
-                    int change = isPackageDisappearing(wallpaper.wallpaperComponent
-                            .getPackageName());
-                    if (change == PACKAGE_PERMANENT_CHANGE
-                            || change == PACKAGE_TEMPORARY_CHANGE) {
-                        changed = true;
-                        if (doit) {
-                            Slog.w(TAG, "Wallpaper uninstalled, removing: "
-                                    + wallpaper.wallpaperComponent);
-                            clearWallpaperLocked(false, wallpaper.userId);
-                        }
-                    }
-                }
-                if (wallpaper.nextWallpaperComponent != null) {
-                    int change = isPackageDisappearing(wallpaper.nextWallpaperComponent
-                            .getPackageName());
-                    if (change == PACKAGE_PERMANENT_CHANGE
-                            || change == PACKAGE_TEMPORARY_CHANGE) {
-                        wallpaper.nextWallpaperComponent = null;
-                    }
-                }
-                if (wallpaper.wallpaperComponent != null
-                        && isPackageModified(wallpaper.wallpaperComponent.getPackageName())) {
-                    try {
-                        mContext.getPackageManager().getServiceInfo(
-                                wallpaper.wallpaperComponent, 0);
-                    } catch (NameNotFoundException e) {
-                        Slog.w(TAG, "Wallpaper component gone, removing: "
+            if (wallpaper.wallpaperComponent != null) {
+                int change = isPackageDisappearing(wallpaper.wallpaperComponent
+                        .getPackageName());
+                if (change == PACKAGE_PERMANENT_CHANGE
+                        || change == PACKAGE_TEMPORARY_CHANGE) {
+                    changed = true;
+                    if (doit) {
+                        Slog.w(TAG, "Wallpaper uninstalled, removing: "
                                 + wallpaper.wallpaperComponent);
                         clearWallpaperLocked(false, wallpaper.userId);
                     }
                 }
-                if (wallpaper.nextWallpaperComponent != null
-                        && isPackageModified(wallpaper.nextWallpaperComponent.getPackageName())) {
-                    try {
-                        mContext.getPackageManager().getServiceInfo(
-                                wallpaper.nextWallpaperComponent, 0);
-                    } catch (NameNotFoundException e) {
-                        wallpaper.nextWallpaperComponent = null;
-                    }
+            }
+            if (wallpaper.nextWallpaperComponent != null) {
+                int change = isPackageDisappearing(wallpaper.nextWallpaperComponent
+                        .getPackageName());
+                if (change == PACKAGE_PERMANENT_CHANGE
+                        || change == PACKAGE_TEMPORARY_CHANGE) {
+                    wallpaper.nextWallpaperComponent = null;
+                }
+            }
+            if (wallpaper.wallpaperComponent != null
+                    && isPackageModified(wallpaper.wallpaperComponent.getPackageName())) {
+                try {
+                    mContext.getPackageManager().getServiceInfo(
+                            wallpaper.wallpaperComponent, 0);
+                } catch (NameNotFoundException e) {
+                    Slog.w(TAG, "Wallpaper component gone, removing: "
+                            + wallpaper.wallpaperComponent);
+                    clearWallpaperLocked(false, wallpaper.userId);
+                }
+            }
+            if (wallpaper.nextWallpaperComponent != null
+                    && isPackageModified(wallpaper.nextWallpaperComponent.getPackageName())) {
+                try {
+                    mContext.getPackageManager().getServiceInfo(
+                            wallpaper.nextWallpaperComponent, 0);
+                } catch (NameNotFoundException e) {
+                    wallpaper.nextWallpaperComponent = null;
                 }
             }
             return changed;
@@ -387,7 +389,7 @@
         mIWindowManager = IWindowManager.Stub.asInterface(
                 ServiceManager.getService(Context.WINDOW_SERVICE));
         mMonitor = new MyPackageMonitor();
-        mMonitor.register(context, true);
+        mMonitor.register(context, null, true);
         WALLPAPER_BASE_DIR.mkdirs();
         loadSettingsLocked(0);
     }
diff --git a/services/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/java/com/android/server/accessibility/AccessibilityManagerService.java
index 6675816..a50db67 100644
--- a/services/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -269,11 +269,11 @@
         };
 
         // package changes
-        monitor.register(context, true);
+        monitor.register(context, null, true);
 
         // boot completed
         IntentFilter bootFiler = new IntentFilter(Intent.ACTION_BOOT_COMPLETED);
-        mContext.registerReceiver(monitor, bootFiler);
+        mContext.registerReceiver(monitor, bootFiler, null, monitor.getRegisteredHandler());
     }
 
     /**
diff --git a/services/java/com/android/server/am/UsageStatsService.java b/services/java/com/android/server/am/UsageStatsService.java
index e810e3c..ba65f39 100644
--- a/services/java/com/android/server/am/UsageStatsService.java
+++ b/services/java/com/android/server/am/UsageStatsService.java
@@ -656,7 +656,7 @@
                 }
             }
         };
-        mPackageMonitor.register(mContext, true);
+        mPackageMonitor.register(mContext, null, true);
         filterHistoryStats();
     }
 
diff --git a/services/java/com/android/server/usb/UsbSettingsManager.java b/services/java/com/android/server/usb/UsbSettingsManager.java
index 0baafbb..7dde340 100644
--- a/services/java/com/android/server/usb/UsbSettingsManager.java
+++ b/services/java/com/android/server/usb/UsbSettingsManager.java
@@ -370,7 +370,7 @@
         synchronized (mLock) {
             readSettingsLocked();
         }
-        mPackageMonitor.register(context, true);
+        mPackageMonitor.register(context, null, true);
     }
 
     private void readPreference(XmlPullParser parser)