Merge "Provide access to ActivityInfo.name from LauncherActivityInfo"
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 75bf5df..b6a41bf 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -44,6 +44,7 @@
 import com.android.internal.app.IVoiceInteractor;
 import com.android.internal.app.ProcessMap;
 import com.android.internal.app.ProcessStats;
+import com.android.internal.content.PackageMonitor;
 import com.android.internal.os.BackgroundThread;
 import com.android.internal.os.BatteryStatsImpl;
 import com.android.internal.os.ProcessCpuTracker;
@@ -1836,6 +1837,78 @@
         }
     };
 
+    /**
+     * Monitor for package changes and update our internal state.
+     */
+    private final PackageMonitor mPackageMonitor = new PackageMonitor() {
+        @Override
+        public void onPackageRemoved(String packageName, int uid) {
+            // Remove all tasks with activities in the specified package from the list of recent tasks
+            synchronized (ActivityManagerService.this) {
+                for (int i = mRecentTasks.size() - 1; i >= 0; i--) {
+                    TaskRecord tr = mRecentTasks.get(i);
+                    ComponentName cn = tr.intent.getComponent();
+                    if (cn != null && cn.getPackageName().equals(packageName)) {
+                        // If the package name matches, remove the task and kill the process
+                        removeTaskByIdLocked(tr.taskId, ActivityManager.REMOVE_TASK_KILL_PROCESS);
+                    }
+                }
+            }
+        }
+
+        @Override
+        public boolean onPackageChanged(String packageName, int uid, String[] components) {
+            final PackageManager pm = mContext.getPackageManager();
+            final ArrayList<TaskRecord> recentTasks = new ArrayList<TaskRecord>();
+            final ArrayList<TaskRecord> tasksToRemove = new ArrayList<TaskRecord>();
+            // Copy the list of recent tasks so that we don't hold onto the lock on
+            // ActivityManagerService for long periods while checking if components exist.
+            synchronized (ActivityManagerService.this) {
+                recentTasks.addAll(mRecentTasks);
+            }
+            // Check the recent tasks and filter out all tasks with components that no longer exist.
+            Intent tmpI = new Intent();
+            for (int i = recentTasks.size() - 1; i >= 0; i--) {
+                TaskRecord tr = recentTasks.get(i);
+                ComponentName cn = tr.intent.getComponent();
+                if (cn != null && cn.getPackageName().equals(packageName)) {
+                    try {
+                        // Add the task to the list to remove if the component no longer exists
+                        tmpI.setComponent(cn);
+                        if (pm.queryIntentActivities(tmpI, PackageManager.MATCH_DEFAULT_ONLY).isEmpty()) {
+                            tasksToRemove.add(tr);
+                        }
+                    } catch (Exception e) {}
+                }
+            }
+            // Prune all the tasks with removed components from the list of recent tasks
+            synchronized (ActivityManagerService.this) {
+                for (int i = tasksToRemove.size() - 1; i >= 0; i--) {
+                    TaskRecord tr = tasksToRemove.get(i);
+                    // Remove the task but don't kill the process
+                    removeTaskByIdLocked(tr.taskId, 0);
+                }
+            }
+            return true;
+        }
+
+        @Override
+        public boolean onHandleForceStop(Intent intent, String[] packages, int uid, boolean doit) {
+            // Force stop the specified packages
+            if (packages != null) {
+                for (String pkg : packages) {
+                    synchronized (ActivityManagerService.this) {
+                        if (forceStopPackageLocked(pkg, -1, false, false, false, false, false, 0,
+                                "finished booting")) {
+                            return true;
+                        }
+                    }
+                }
+            }
+            return false;
+        }
+    };
+
     public void setSystemProcess() {
         try {
             ServiceManager.addService(Context.ACTIVITY_SERVICE, this, true);
@@ -5267,26 +5340,8 @@
     }
 
     final void finishBooting() {
-        IntentFilter pkgFilter = new IntentFilter();
-        pkgFilter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
-        pkgFilter.addDataScheme("package");
-        mContext.registerReceiver(new BroadcastReceiver() {
-            @Override
-            public void onReceive(Context context, Intent intent) {
-                String[] pkgs = intent.getStringArrayExtra(Intent.EXTRA_PACKAGES);
-                if (pkgs != null) {
-                    for (String pkg : pkgs) {
-                        synchronized (ActivityManagerService.this) {
-                            if (forceStopPackageLocked(pkg, -1, false, false, false, false, false, 0,
-                                    "finished booting")) {
-                                setResultCode(Activity.RESULT_OK);
-                                return;
-                            }
-                        }
-                    }
-                }
-            }
-        }, pkgFilter);
+        // Register receivers to handle package update events
+        mPackageMonitor.register(mContext, Looper.getMainLooper(), false);
 
         synchronized (this) {
             // Ensure that any processes we had put on hold are now started
diff --git a/tools/aapt/Resource.cpp b/tools/aapt/Resource.cpp
index 6d9d62e..d0581f6 100644
--- a/tools/aapt/Resource.cpp
+++ b/tools/aapt/Resource.cpp
@@ -2462,7 +2462,7 @@
 
 status_t
 writeProguardForXml(ProguardKeepSet* keep, const sp<AaptFile>& layoutFile,
-        const char* startTag, const KeyedVector<String8, Vector<NamespaceAttributePair> >* tagAttrPairs)
+        const Vector<String8>& startTags, const KeyedVector<String8, Vector<NamespaceAttributePair> >* tagAttrPairs)
 {
     status_t err;
     ResXMLTree tree;
@@ -2476,15 +2476,18 @@
 
     tree.restart();
 
-    if (startTag != NULL) {
+    if (!startTags.isEmpty()) {
         bool haveStart = false;
         while ((code=tree.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) {
             if (code != ResXMLTree::START_TAG) {
                 continue;
             }
             String8 tag(tree.getElementName(&len));
-            if (tag == startTag) {
-                haveStart = true;
+            const size_t numStartTags = startTags.size();
+            for (size_t i = 0; i < numStartTags; i++) {
+                if (tag == startTags[i]) {
+                    haveStart = true;
+                }
             }
             break;
         }
@@ -2571,15 +2574,17 @@
     for (size_t k=0; k<K; k++) {
         const sp<AaptDir>& d = dirs.itemAt(k);
         const String8& dirName = d->getLeaf();
+        Vector<String8> startTags;
         const char* startTag = NULL;
         const KeyedVector<String8, Vector<NamespaceAttributePair> >* tagAttrPairs = NULL;
         if ((dirName == String8("layout")) || (strncmp(dirName.string(), "layout-", 7) == 0)) {
             tagAttrPairs = &kLayoutTagAttrPairs;
         } else if ((dirName == String8("xml")) || (strncmp(dirName.string(), "xml-", 4) == 0)) {
-            startTag = "PreferenceScreen";
+            startTags.add(String8("PreferenceScreen"));
+            startTags.add(String8("preference-headers"));
             tagAttrPairs = &kXmlTagAttrPairs;
         } else if ((dirName == String8("menu")) || (strncmp(dirName.string(), "menu-", 5) == 0)) {
-            startTag = "menu";
+            startTags.add(String8("menu"));
             tagAttrPairs = NULL;
         } else {
             continue;
@@ -2592,7 +2597,7 @@
             const DefaultKeyedVector<AaptGroupEntry, sp<AaptFile> >& files = group->getFiles();
             const size_t M = files.size();
             for (size_t j=0; j<M; j++) {
-                err = writeProguardForXml(keep, files.valueAt(j), startTag, tagAttrPairs);
+                err = writeProguardForXml(keep, files.valueAt(j), startTags, tagAttrPairs);
                 if (err < 0) {
                     return err;
                 }