am 65b2561c: Merge "Fix issue #2643754: Launcher is caching widget layouts for too long" into froyo

Merge commit '65b2561c3bd74b639df0fead2041c775b7f40000' into froyo-plus-aosp

* commit '65b2561c3bd74b639df0fead2041c775b7f40000':
  Fix issue #2643754: Launcher is caching widget layouts for too long
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index fd84859..773c344 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -194,6 +194,7 @@
             }
             WeakReference<Resources> wr = mActiveResources.get(key);
             r = wr != null ? wr.get() : null;
+            //if (r != null) Slog.i(TAG, "isUpToDate " + resDir + ": " + r.getAssets().isUpToDate());
             if (r != null && r.getAssets().isUpToDate()) {
                 if (false) {
                     Slog.w(TAG, "Returning cached resources " + r + " " + resDir
@@ -1752,6 +1753,10 @@
             Debug.getMemoryInfo(outInfo);
         }
 
+        public void dispatchPackageBroadcast(int cmd, String[] packages) {
+            queueOrSendMessage(H.DISPATCH_PACKAGE_BROADCAST, packages, cmd);
+        }
+        
         @Override
         protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
             long nativeMax = Debug.getNativeHeapSize() / 1024;
@@ -1976,6 +1981,7 @@
         public static final int SUICIDE                 = 130;
         public static final int REMOVE_PROVIDER         = 131;
         public static final int ENABLE_JIT              = 132;
+        public static final int DISPATCH_PACKAGE_BROADCAST = 133;
         String codeToString(int code) {
             if (localLOGV) {
                 switch (code) {
@@ -2012,6 +2018,7 @@
                     case SUICIDE: return "SUICIDE";
                     case REMOVE_PROVIDER: return "REMOVE_PROVIDER";
                     case ENABLE_JIT: return "ENABLE_JIT";
+                    case DISPATCH_PACKAGE_BROADCAST: return "DISPATCH_PACKAGE_BROADCAST";
                 }
             }
             return "(unknown)";
@@ -2132,6 +2139,9 @@
                 case ENABLE_JIT:
                     ensureJitEnabled();
                     break;
+                case DISPATCH_PACKAGE_BROADCAST:
+                    handleDispatchPackageBroadcast(msg.arg1, (String[])msg.obj);
+                    break;
             }
         }
 
@@ -2239,16 +2249,16 @@
     // XXX For now we keep around information about all packages we have
     // seen, not removing entries from this map.
     final HashMap<String, WeakReference<PackageInfo>> mPackages
-        = new HashMap<String, WeakReference<PackageInfo>>();
+            = new HashMap<String, WeakReference<PackageInfo>>();
     final HashMap<String, WeakReference<PackageInfo>> mResourcePackages
-        = new HashMap<String, WeakReference<PackageInfo>>();
+            = new HashMap<String, WeakReference<PackageInfo>>();
     Display mDisplay = null;
     DisplayMetrics mDisplayMetrics = null;
-    HashMap<ResourcesKey, WeakReference<Resources> > mActiveResources
-        = new HashMap<ResourcesKey, WeakReference<Resources> >();
+    final HashMap<ResourcesKey, WeakReference<Resources> > mActiveResources
+            = new HashMap<ResourcesKey, WeakReference<Resources> >();
     final ArrayList<ActivityRecord> mRelaunchingActivities
             = new ArrayList<ActivityRecord>();
-        Configuration mPendingConfiguration = null;
+    Configuration mPendingConfiguration = null;
 
     // The lock of mProviderMap protects the following variables.
     final HashMap<String, ProviderRecord> mProviderMap
@@ -2271,6 +2281,8 @@
             }
             PackageInfo packageInfo = ref != null ? ref.get() : null;
             //Slog.i(TAG, "getPackageInfo " + packageName + ": " + packageInfo);
+            //if (packageInfo != null) Slog.i(TAG, "isUptoDate " + packageInfo.mResDir
+            //        + ": " + packageInfo.mResources.getAssets().isUpToDate());
             if (packageInfo != null && (packageInfo.mResources == null
                     || packageInfo.mResources.getAssets().isUpToDate())) {
                 if (packageInfo.isSecurityViolation()
@@ -2358,21 +2370,6 @@
         }
     }
 
-    public final boolean hasPackageInfo(String packageName) {
-        synchronized (mPackages) {
-            WeakReference<PackageInfo> ref;
-            ref = mPackages.get(packageName);
-            if (ref != null && ref.get() != null) {
-                return true;
-            }
-            ref = mResourcePackages.get(packageName);
-            if (ref != null && ref.get() != null) {
-                return true;
-            }
-            return false;
-        }
-    }
-
     ActivityThread() {
     }
 
@@ -4054,6 +4051,31 @@
         }
     }
 
+    final void handleDispatchPackageBroadcast(int cmd, String[] packages) {
+        boolean hasPkgInfo = false;
+        if (packages != null) {
+            for (int i=packages.length-1; i>=0; i--) {
+                //Slog.i(TAG, "Cleaning old package: " + packages[i]);
+                if (!hasPkgInfo) {
+                    WeakReference<PackageInfo> ref;
+                    ref = mPackages.get(packages[i]);
+                    if (ref != null && ref.get() != null) {
+                        hasPkgInfo = true;
+                    } else {
+                        ref = mResourcePackages.get(packages[i]);
+                        if (ref != null && ref.get() != null) {
+                            hasPkgInfo = true;
+                        }
+                    }
+                }
+                mPackages.remove(packages[i]);
+                mResourcePackages.remove(packages[i]);
+            }
+        }
+        ContextImpl.ApplicationPackageManager.handlePackageBroadcast(cmd, packages,
+                hasPkgInfo);
+    }
+        
     final void handleLowMemory() {
         ArrayList<ComponentCallbacks> callbacks
                 = new ArrayList<ComponentCallbacks>();
diff --git a/core/java/android/app/ApplicationThreadNative.java b/core/java/android/app/ApplicationThreadNative.java
index 7cba13f..da26a78 100644
--- a/core/java/android/app/ApplicationThreadNative.java
+++ b/core/java/android/app/ApplicationThreadNative.java
@@ -393,6 +393,15 @@
             mi.writeToParcel(reply, 0);
             return true;
         }
+
+        case DISPATCH_PACKAGE_BROADCAST_TRANSACTION:
+        {
+            data.enforceInterface(IApplicationThread.descriptor);
+            int cmd = data.readInt();
+            String[] packages = data.readStringArray();
+            dispatchPackageBroadcast(cmd, packages);
+            return true;
+        }
         }
 
         return super.onTransact(code, data, reply, flags);
@@ -806,5 +815,16 @@
         data.recycle();
         reply.recycle();
     }
+    
+    public void dispatchPackageBroadcast(int cmd, String[] packages) throws RemoteException {
+        Parcel data = Parcel.obtain();
+        data.writeInterfaceToken(IApplicationThread.descriptor);
+        data.writeInt(cmd);
+        data.writeStringArray(packages);
+        mRemote.transact(DISPATCH_PACKAGE_BROADCAST_TRANSACTION, data, null,
+                IBinder.FLAG_ONEWAY);
+        data.recycle();
+        
+    }
 }
 
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index fd0edaa..f471f57 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -2244,33 +2244,7 @@
             return null;
         }
 
-        private void establishPackageRemovedReceiver() {
-            // mContext.registerReceiverInternal() winds up acquiring the
-            // main ActivityManagerService.this lock.  If we hold our usual
-            // sSync global lock at the same time, we impose a required ordering
-            // on those two locks, which is not good for deadlock prevention.
-            // Use a dedicated lock around initialization of
-            // sPackageRemovedReceiver to avoid this.
-            synchronized (sPackageRemovedSync) {
-                if (sPackageRemovedReceiver == null) {
-                    sPackageRemovedReceiver = new PackageRemovedReceiver();
-                    IntentFilter filter = new IntentFilter(
-                            Intent.ACTION_PACKAGE_REMOVED);
-                    filter.addDataScheme("package");
-                    mContext.registerReceiverInternal(sPackageRemovedReceiver,
-                            filter, null, null, null);
-                    // Register for events related to sdcard installation.
-                    IntentFilter sdFilter = new IntentFilter();
-                    sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
-                    mContext.registerReceiverInternal(sPackageRemovedReceiver,
-                            sdFilter, null, null, null);
-                }
-            }
-        }
-        
         private void putCachedIcon(ResourceName name, Drawable dr) {
-            establishPackageRemovedReceiver();
-
             synchronized (sSync) {
                 sIconCache.put(name, new WeakReference<Drawable>(dr));
                 if (DEBUG_ICONS) Log.v(TAG, "Added cached drawable for "
@@ -2278,29 +2252,17 @@
             }
         }
 
-        private static final class PackageRemovedReceiver extends BroadcastReceiver {
-            @Override
-            public void onReceive(Context context, Intent intent) {
-                String pkgList[] = null;
-                String action = intent.getAction();
-                boolean immediateGc = false;
-                if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) {
-                    pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
-                    immediateGc = true;
-                } else {
-                    Uri data = intent.getData();
-                    if (data != null) {
-                        String ssp = data.getSchemeSpecificPart();
-                        if (ssp != null) {
-                            pkgList = new String[] { ssp };
-                        }
-                    }
-                }
-                if (pkgList != null && (pkgList.length > 0)) {
-                    boolean needCleanup = false;
-                    boolean hasPkgInfo = false;
-                    for (String ssp : pkgList) {
-                        synchronized (sSync) {
+        static final void handlePackageBroadcast(int cmd, String[] pkgList,
+                boolean hasPkgInfo) {
+            boolean immediateGc = false;
+            if (cmd == IApplicationThread.EXTERNAL_STORAGE_UNAVAILABLE) {
+                immediateGc = true;
+            }
+            if (pkgList != null && (pkgList.length > 0)) {
+                boolean needCleanup = false;
+                for (String ssp : pkgList) {
+                    synchronized (sSync) {
+                        if (sIconCache.size() > 0) {
                             Iterator<ResourceName> it = sIconCache.keySet().iterator();
                             while (it.hasNext()) {
                                 ResourceName nm = it.next();
@@ -2310,7 +2272,9 @@
                                     needCleanup = true;
                                 }
                             }
-                            it = sStringCache.keySet().iterator();
+                        }
+                        if (sStringCache.size() > 0) {
+                            Iterator<ResourceName> it = sStringCache.keySet().iterator();
                             while (it.hasNext()) {
                                 ResourceName nm = it.next();
                                 if (nm.packageName.equals(ssp)) {
@@ -2320,22 +2284,19 @@
                                 }
                             }
                         }
-                        if (!hasPkgInfo) {
-                            hasPkgInfo = ActivityThread.currentActivityThread().hasPackageInfo(ssp);
-                        }
                     }
-                    if (needCleanup || hasPkgInfo) {
-                        if (immediateGc) {
-                            // Schedule an immediate gc.
-                            Runtime.getRuntime().gc();
-                        } else {
-                            ActivityThread.currentActivityThread().scheduleGcIdler();
-                        }
+                }
+                if (needCleanup || hasPkgInfo) {
+                    if (immediateGc) {
+                        // Schedule an immediate gc.
+                        Runtime.getRuntime().gc();
+                    } else {
+                        ActivityThread.currentActivityThread().scheduleGcIdler();
                     }
                 }
             }
         }
-
+        
         private static final class ResourceName {
             final String packageName;
             final int iconId;
@@ -2400,8 +2361,6 @@
         }
 
         private void putCachedString(ResourceName name, CharSequence cs) {
-            establishPackageRemovedReceiver();
-
             synchronized (sSync) {
                 sStringCache.put(name, new WeakReference<CharSequence>(cs));
             }
@@ -2665,8 +2624,6 @@
         private final IPackageManager mPM;
 
         private static final Object sSync = new Object();
-        private static final Object sPackageRemovedSync = new Object();
-        private static BroadcastReceiver sPackageRemovedReceiver;
         private static HashMap<ResourceName, WeakReference<Drawable> > sIconCache
                 = new HashMap<ResourceName, WeakReference<Drawable> >();
         private static HashMap<ResourceName, WeakReference<CharSequence> > sStringCache
diff --git a/core/java/android/app/IApplicationThread.java b/core/java/android/app/IApplicationThread.java
index ed810d3..c917e81 100644
--- a/core/java/android/app/IApplicationThread.java
+++ b/core/java/android/app/IApplicationThread.java
@@ -100,6 +100,9 @@
             throws RemoteException;
     void setSchedulingGroup(int group) throws RemoteException;
     void getMemoryInfo(Debug.MemoryInfo outInfo) throws RemoteException;
+    static final int PACKAGE_REMOVED = 0;
+    static final int EXTERNAL_STORAGE_UNAVAILABLE = 1;
+    void dispatchPackageBroadcast(int cmd, String[] packages) throws RemoteException;
     
     String descriptor = "android.app.IApplicationThread";
 
@@ -135,4 +138,5 @@
     int SCHEDULE_DESTROY_BACKUP_AGENT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+30;
     int GET_MEMORY_INFO_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+31;
     int SCHEDULE_SUICIDE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+32;
+    int DISPATCH_PACKAGE_BROADCAST_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+33;
 }
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 8383ca3..706e15a 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -12269,6 +12269,18 @@
         }
     }
     
+    private final void sendPackageBroadcastLocked(int cmd, String[] packages) {
+        for (int i = mLruProcesses.size() - 1 ; i >= 0 ; i--) {
+            ProcessRecord r = mLruProcesses.get(i);
+            if (r.thread != null) {
+                try {
+                    r.thread.dispatchPackageBroadcast(cmd, packages);
+                } catch (RemoteException ex) {
+                }
+            }
+        }
+    }
+    
     private final int broadcastIntentLocked(ProcessRecord callerApp,
             String callerPackage, Intent intent, String resolvedType,
             IIntentReceiver resultTo, int resultCode, String resultData,
@@ -12315,6 +12327,8 @@
                             for (String pkg : list) {
                                 forceStopPackageLocked(pkg, -1, false, true, true);
                             }
+                            sendPackageBroadcastLocked(
+                                    IApplicationThread.EXTERNAL_STORAGE_UNAVAILABLE, list);
                         }
                     } else {
                         Uri data = intent.getData();
@@ -12324,6 +12338,10 @@
                                 forceStopPackageLocked(ssp,
                                         intent.getIntExtra(Intent.EXTRA_UID, -1), false, true, true);
                             }
+                            if (intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())) {
+                                sendPackageBroadcastLocked(IApplicationThread.PACKAGE_REMOVED,
+                                        new String[] {ssp});
+                            }
                         }
                     }
                 }