Merge "Fix DevicePolicyManager crash when settings password quality (and possibly others)." into jb-mr1-dev
diff --git a/api/current.txt b/api/current.txt
index 9d7bb14..c1d8c9e 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -3353,6 +3353,7 @@
     method public final android.app.FragmentManager getFragmentManager();
     method public final int getId();
     method public android.app.LoaderManager getLoaderManager();
+    method public final android.app.Fragment getParentFragment();
     method public final android.content.res.Resources getResources();
     method public final boolean getRetainInstance();
     method public final java.lang.String getString(int);
@@ -18383,6 +18384,7 @@
     field public static final java.lang.String INTENT_ACTION_MEDIA_SEARCH = "android.intent.action.MEDIA_SEARCH";
     field public static final deprecated java.lang.String INTENT_ACTION_MUSIC_PLAYER = "android.intent.action.MUSIC_PLAYER";
     field public static final java.lang.String INTENT_ACTION_STILL_IMAGE_CAMERA = "android.media.action.STILL_IMAGE_CAMERA";
+    field public static final java.lang.String INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE = "android.media.action.STILL_IMAGE_CAMERA_SECURE";
     field public static final java.lang.String INTENT_ACTION_VIDEO_CAMERA = "android.media.action.VIDEO_CAMERA";
     field public static final java.lang.String MEDIA_IGNORE_FILENAME = ".nomedia";
     field public static final java.lang.String MEDIA_SCANNER_VOLUME = "volume";
diff --git a/cmds/svc/src/com/android/commands/svc/PowerCommand.java b/cmds/svc/src/com/android/commands/svc/PowerCommand.java
index ec3ec3e..58105fa 100644
--- a/cmds/svc/src/com/android/commands/svc/PowerCommand.java
+++ b/cmds/svc/src/com/android/commands/svc/PowerCommand.java
@@ -16,14 +16,12 @@
 
 package com.android.commands.svc;
 
-import android.os.Binder;
-import android.os.IBinder;
-import android.os.IPowerManager;
-import android.os.PowerManager;
-import android.os.ServiceManager;
-import android.os.RemoteException;
-import android.os.BatteryManager;
 import android.content.Context;
+import android.os.BatteryManager;
+import android.os.IPowerManager;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.SystemClock;
 
 public class PowerCommand extends Svc.Command {
     public PowerCommand() {
@@ -65,10 +63,12 @@
                     IPowerManager pm
                             = IPowerManager.Stub.asInterface(ServiceManager.getService(Context.POWER_SERVICE));
                     try {
-                        IBinder lock = new Binder();
-                        pm.acquireWakeLock(lock, PowerManager.FULL_WAKE_LOCK, "svc power", null);
+                        if (val != 0) {
+                            // if the request is not to set it to false, wake up the screen so that
+                            // it can stay on as requested
+                            pm.wakeUp(SystemClock.uptimeMillis());
+                        }
                         pm.setStayOnSetting(val);
-                        pm.releaseWakeLock(lock, 0);
                     }
                     catch (RemoteException e) {
                         System.err.println("Faild to set setting: " + e);
diff --git a/core/java/android/app/Fragment.java b/core/java/android/app/Fragment.java
index 3ff9df5..c5a382d 100644
--- a/core/java/android/app/Fragment.java
+++ b/core/java/android/app/Fragment.java
@@ -615,7 +615,7 @@
                     + " did not call through to super.onViewStateRestored()");
         }
     }
-    
+
     final void setIndex(int index, Fragment parent) {
         mIndex = index;
         if (parent != null) {
@@ -623,8 +623,8 @@
         } else {
             mWho = "android:fragment:" + mIndex;
         }
-   }
-    
+    }
+
     final boolean isInBackStack() {
         return mBackStackNesting > 0;
     }
@@ -832,6 +832,14 @@
     }
 
     /**
+     * Returns the parent Fragment containing this Fragment.  If this Fragment
+     * is attached directly to an Activity, returns null.
+     */
+    final public Fragment getParentFragment() {
+        return mParentFragment;
+    }
+
+    /**
      * Return true if the fragment is currently added to its activity.
      */
     final public boolean isAdded() {
@@ -1180,20 +1188,7 @@
     public void onCreate(Bundle savedInstanceState) {
         mCalled = true;
     }
-    
-    /**
-     * Called immediately after {@link #onCreateView(LayoutInflater, ViewGroup, Bundle)}
-     * has returned, but before any saved state has been restored in to the view.
-     * This gives subclasses a chance to initialize themselves once
-     * they know their view hierarchy has been completely created.  The fragment's
-     * view hierarchy is not however attached to its parent at this point.
-     * @param view The View returned by {@link #onCreateView(LayoutInflater, ViewGroup, Bundle)}.
-     * @param savedInstanceState If non-null, this fragment is being re-constructed
-     * from a previous saved state as given here.
-     */
-    public void onViewCreated(View view, Bundle savedInstanceState) {
-    }
-    
+
     /**
      * Called to have the fragment instantiate its user interface view.
      * This is optional, and non-graphical fragments can return null (which
@@ -1217,6 +1212,19 @@
             Bundle savedInstanceState) {
         return null;
     }
+
+    /**
+     * Called immediately after {@link #onCreateView(LayoutInflater, ViewGroup, Bundle)}
+     * has returned, but before any saved state has been restored in to the view.
+     * This gives subclasses a chance to initialize themselves once
+     * they know their view hierarchy has been completely created.  The fragment's
+     * view hierarchy is not however attached to its parent at this point.
+     * @param view The View returned by {@link #onCreateView(LayoutInflater, ViewGroup, Bundle)}.
+     * @param savedInstanceState If non-null, this fragment is being re-constructed
+     * from a previous saved state as given here.
+     */
+    public void onViewCreated(View view, Bundle savedInstanceState) {
+    }
     
     /**
      * Get the root view for the fragment's layout (the one returned by {@link #onCreateView}),
@@ -1237,7 +1245,7 @@
      * as this callback tells the fragment when it is fully associated with
      * the new activity instance.  This is called after {@link #onCreateView}
      * and before {@link #onViewStateRestored(Bundle)}.
-     * 
+     *
      * @param savedInstanceState If the fragment is being re-created from
      * a previous saved state, this is the state.
      */
@@ -1252,7 +1260,7 @@
      * whether check box widgets are currently checked.  This is called
      * after {@link #onActivityCreated(Bundle)} and before
      * {@link #onStart()}.
-     * 
+     *
      * @param savedInstanceState If the fragment is being re-created from
      * a previous saved state, this is the state.
      */
@@ -1590,10 +1598,6 @@
             writer.print(prefix); writer.print("mActivity=");
                     writer.println(mActivity);
         }
-        if (mChildFragmentManager != null) {
-            writer.print(prefix); writer.print("mChildFragmentManager=");
-                    writer.println(mChildFragmentManager);
-        }
         if (mParentFragment != null) {
             writer.print(prefix); writer.print("mParentFragment=");
                     writer.println(mParentFragment);
@@ -1633,7 +1637,7 @@
             mLoaderManager.dump(prefix + "  ", fd, writer, args);
         }
         if (mChildFragmentManager != null) {
-            writer.print(prefix); writer.println("Child Fragment Manager:");
+            writer.print(prefix); writer.println("Child " + mChildFragmentManager + ":");
             mChildFragmentManager.dump(prefix + "  ", fd, writer, args);
         }
     }
@@ -1662,6 +1666,9 @@
     }
 
     void performCreate(Bundle savedInstanceState) {
+        if (mChildFragmentManager != null) {
+            mChildFragmentManager.noteStateNotSaved();
+        }
         mCalled = false;
         onCreate(savedInstanceState);
         if (!mCalled) {
@@ -1680,7 +1687,18 @@
         }
     }
 
+    View performCreateView(LayoutInflater inflater, ViewGroup container,
+            Bundle savedInstanceState) {
+        if (mChildFragmentManager != null) {
+            mChildFragmentManager.noteStateNotSaved();
+        }
+        return onCreateView(inflater, container, savedInstanceState);
+    }
+
     void performActivityCreated(Bundle savedInstanceState) {
+        if (mChildFragmentManager != null) {
+            mChildFragmentManager.noteStateNotSaved();
+        }
         mCalled = false;
         onActivityCreated(savedInstanceState);
         if (!mCalled) {
@@ -1713,6 +1731,7 @@
 
     void performResume() {
         if (mChildFragmentManager != null) {
+            mChildFragmentManager.noteStateNotSaved();
             mChildFragmentManager.execPendingActions();
         }
         mCalled = false;
diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java
index eaaf0d7..7f11437 100644
--- a/core/java/android/app/FragmentManager.java
+++ b/core/java/android/app/FragmentManager.java
@@ -834,7 +834,9 @@
                         throw new SuperNotCalledException("Fragment " + f
                                 + " did not call through to super.onAttach()");
                     }
-                    mActivity.onAttachFragment(f);
+                    if (f.mParentFragment == null) {
+                        mActivity.onAttachFragment(f);
+                    }
 
                     if (!f.mRetaining) {
                         f.performCreate(f.mSavedFragmentState);
@@ -844,8 +846,8 @@
                         // For fragments that are part of the content view
                         // layout, we need to instantiate the view immediately
                         // and the inflater will take care of adding it.
-                        f.mView = f.onCreateView(f.getLayoutInflater(f.mSavedFragmentState),
-                                null, f.mSavedFragmentState);
+                        f.mView = f.performCreateView(f.getLayoutInflater(
+                                f.mSavedFragmentState), null, f.mSavedFragmentState);
                         if (f.mView != null) {
                             f.mView.setSaveFromParentEnabled(false);
                             if (f.mHidden) f.mView.setVisibility(View.GONE);
@@ -868,8 +870,8 @@
                                 }
                             }
                             f.mContainer = container;
-                            f.mView = f.onCreateView(f.getLayoutInflater(f.mSavedFragmentState),
-                                    container, f.mSavedFragmentState);
+                            f.mView = f.performCreateView(f.getLayoutInflater(
+                                    f.mSavedFragmentState), container, f.mSavedFragmentState);
                             if (f.mView != null) {
                                 f.mView.setSaveFromParentEnabled(false);
                                 if (container != null) {
@@ -885,7 +887,7 @@
                                 f.onViewCreated(f.mView, f.mSavedFragmentState);
                             }
                         }
-                        
+
                         f.performActivityCreated(f.mSavedFragmentState);
                         if (f.mView != null) {
                             f.restoreViewState(f.mSavedFragmentState);
@@ -1824,7 +1826,7 @@
     public void dispatchDestroyView() {
         moveToState(Fragment.CREATED, false);
     }
-    
+
     public void dispatchDestroy() {
         mDestroyed = true;
         execPendingActions();
diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java
index 48d84c1..3c2d164 100644
--- a/core/java/android/provider/MediaStore.java
+++ b/core/java/android/provider/MediaStore.java
@@ -183,8 +183,6 @@
      * on top of the lock screen while secured. There is no activity stack when
      * this flag is used, so launching more than one activity is strongly
      * discouraged.
-     *
-     * @hide
      */
     public static final String INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE =
             "android.media.action.STILL_IMAGE_CAMERA_SECURE";
diff --git a/core/tests/coretests/apks/FrameworkCoreTests_apk.mk b/core/tests/coretests/apks/FrameworkCoreTests_apk.mk
index ac545ca..1e03270 100644
--- a/core/tests/coretests/apks/FrameworkCoreTests_apk.mk
+++ b/core/tests/coretests/apks/FrameworkCoreTests_apk.mk
@@ -7,6 +7,9 @@
 # Make sure every package name gets the FrameworkCoreTests_ prefix.
 LOCAL_PACKAGE_NAME := FrameworkCoreTests_$(LOCAL_PACKAGE_NAME)
 
+# Every package should have a native library
+LOCAL_JNI_SHARED_LIBRARIES := libframeworks_coretests_jni
+
 FrameworkCoreTests_all_apks += $(LOCAL_PACKAGE_NAME)
 
 include $(BUILD_PACKAGE)
diff --git a/core/tests/coretests/apks/install_jni_lib/Android.mk b/core/tests/coretests/apks/install_jni_lib/Android.mk
new file mode 100644
index 0000000..de2993a
--- /dev/null
+++ b/core/tests/coretests/apks/install_jni_lib/Android.mk
@@ -0,0 +1,28 @@
+# Copyright (C) 2012 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 the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+    com_android_frameworks_coretests_JNITest.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+    libnativehelper
+
+LOCAL_MODULE := libframeworks_coretests_jni
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/core/tests/coretests/apks/install_jni_lib/com_android_frameworks_coretests_JNITest.cpp b/core/tests/coretests/apks/install_jni_lib/com_android_frameworks_coretests_JNITest.cpp
new file mode 100644
index 0000000..957fc4a
--- /dev/null
+++ b/core/tests/coretests/apks/install_jni_lib/com_android_frameworks_coretests_JNITest.cpp
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2012 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 the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "nativehelper/JNIHelp.h"
+
+namespace android {
+
+static jint checkFunction(JNIEnv*, jclass) {
+    return 1;
+}
+
+static JNINativeMethod sMethods[] = {
+    /* name, signature, funcPtr */
+    { "checkFunction", "()I", (void*) checkFunction },
+};
+
+int register_com_android_framework_coretests_JNITests(JNIEnv* env) {
+    return jniRegisterNativeMethods(env, "com/android/framework/coretests/JNITests", sMethods,
+            NELEM(sMethods));
+}
+
+}
+
+/*
+ * JNI Initialization
+ */
+jint JNI_OnLoad(JavaVM *jvm, void *reserved) {
+    JNIEnv *e;
+    int status;
+
+    // Check JNI version
+    if (jvm->GetEnv((void **) &e, JNI_VERSION_1_6)) {
+        return JNI_ERR;
+    }
+
+    if ((status = android::register_com_android_framework_coretests_JNITests(e)) < 0) {
+        return JNI_ERR;
+    }
+
+    return JNI_VERSION_1_6;
+}
diff --git a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
index f46478c..1868d1c 100755
--- a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
+++ b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
@@ -16,6 +16,8 @@
 
 package android.content.pm;
 
+import static libcore.io.OsConstants.*;
+
 import com.android.frameworks.coretests.R;
 import com.android.internal.content.PackageHelper;
 
@@ -32,9 +34,11 @@
 import android.os.Environment;
 import android.os.FileUtils;
 import android.os.IBinder;
+import android.os.Process;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.StatFs;
+import android.os.SystemClock;
 import android.os.storage.IMountService;
 import android.os.storage.StorageListener;
 import android.os.storage.StorageManager;
@@ -52,6 +56,12 @@
 import java.io.InputStream;
 
 import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import libcore.io.ErrnoException;
+import libcore.io.Libcore;
+import libcore.io.StructStat;
 
 public class PackageManagerTests extends AndroidTestCase {
     private static final boolean localLOGV = true;
@@ -404,15 +414,12 @@
                 if ((flags & PackageManager.INSTALL_FORWARD_LOCK) != 0) {
                     assertTrue("The application should be installed forward locked",
                             (info.flags & ApplicationInfo.FLAG_FORWARD_LOCK) != 0);
-                    assertTrue("The APK path (" + srcPath + ") should start with "
-                            + SECURE_CONTAINERS_PREFIX,
-                            srcPath.startsWith(SECURE_CONTAINERS_PREFIX));
-                    assertTrue("The public APK path (" + publicSrcPath + ") should start with "
-                            + SECURE_CONTAINERS_PREFIX,
-                            publicSrcPath.startsWith(SECURE_CONTAINERS_PREFIX));
-                    assertTrue("The native library path (" + info.nativeLibraryDir
-                            + ") should start with " + SECURE_CONTAINERS_PREFIX,
-                            info.nativeLibraryDir.startsWith(SECURE_CONTAINERS_PREFIX));
+                    assertStartsWith("The APK path should point to the ASEC",
+                            SECURE_CONTAINERS_PREFIX, srcPath);
+                    assertStartsWith("The public APK path should point to the ASEC",
+                            SECURE_CONTAINERS_PREFIX, publicSrcPath);
+                    assertStartsWith("The native library path should point to the ASEC",
+                            SECURE_CONTAINERS_PREFIX, info.nativeLibraryDir);
                     try {
                         String compatLib = new File(info.dataDir + "/lib").getCanonicalPath();
                         assertEquals("The compatibility lib directory should be a symbolic link to "
@@ -425,7 +432,14 @@
                     assertFalse((info.flags & ApplicationInfo.FLAG_FORWARD_LOCK) != 0);
                     assertEquals(srcPath, appInstallPath);
                     assertEquals(publicSrcPath, appInstallPath);
-                    assertTrue(info.nativeLibraryDir.startsWith(dataDir.getPath()));
+                    assertStartsWith("Native library should point to shared lib directory",
+                            dataDir.getPath(),
+                            info.nativeLibraryDir);
+                    assertDirOwnerGroupPerms(
+                            "Native library directory should be owned by system:system and 0755",
+                            Process.SYSTEM_UID, Process.SYSTEM_UID,
+                            S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH,
+                            info.nativeLibraryDir);
                 }
                 assertFalse((info.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0);
 
@@ -435,8 +449,7 @@
                         nativeLibDir.exists());
                 try {
                     assertEquals("Native library dir should not be a symlink",
-                            info.nativeLibraryDir,
-                            nativeLibDir.getCanonicalPath());
+                            info.nativeLibraryDir, nativeLibDir.getCanonicalPath());
                 } catch (IOException e) {
                     fail("Can't read " + nativeLibDir.getPath());
                 }
@@ -453,14 +466,12 @@
                         (info.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0);
                 // Might need to check:
                 // ((info.flags & ApplicationInfo.FLAG_FORWARD_LOCK) != 0)
-                assertTrue("The APK path (" + srcPath + ") should start with "
-                        + SECURE_CONTAINERS_PREFIX, srcPath.startsWith(SECURE_CONTAINERS_PREFIX));
-                assertTrue("The public APK path (" + publicSrcPath + ") should start with "
-                        + SECURE_CONTAINERS_PREFIX,
-                        publicSrcPath.startsWith(SECURE_CONTAINERS_PREFIX));
-                assertTrue("The native library path (" + info.nativeLibraryDir
-                        + ") should start with " + SECURE_CONTAINERS_PREFIX,
-                        info.nativeLibraryDir.startsWith(SECURE_CONTAINERS_PREFIX));
+                assertStartsWith("The APK path should point to the ASEC",
+                        SECURE_CONTAINERS_PREFIX, srcPath);
+                assertStartsWith("The public APK path should point to the ASEC",
+                        SECURE_CONTAINERS_PREFIX, publicSrcPath);
+                assertStartsWith("The native library path should point to the ASEC",
+                        SECURE_CONTAINERS_PREFIX, info.nativeLibraryDir);
 
                 // Make sure the native library in /data/data/<app>/lib is a
                 // symlink to the ASEC
@@ -483,6 +494,66 @@
         }
     }
 
+    private void assertDirOwnerGroupPerms(String reason, int uid, int gid, int perms, String path) {
+        final StructStat stat;
+
+        try {
+            stat = Libcore.os.lstat(path);
+        } catch (ErrnoException e) {
+            throw new AssertionError(reason + "\n" + "Got: " + path + " does not exist");
+        }
+
+        StringBuilder sb = new StringBuilder();
+
+        if (!S_ISDIR(stat.st_mode)) {
+            sb.append("\nExpected type: ");
+            sb.append(S_IFDIR);
+            sb.append("\ngot type: ");
+            sb.append((stat.st_mode & S_IFMT));
+        }
+
+        if (stat.st_uid != uid) {
+            sb.append("\nExpected owner: ");
+            sb.append(uid);
+            sb.append("\nGot owner: ");
+            sb.append(stat.st_uid);
+        }
+
+        if (stat.st_gid != gid) {
+            sb.append("\nExpected group: ");
+            sb.append(gid);
+            sb.append("\nGot group: ");
+            sb.append(stat.st_gid);
+        }
+
+        if ((stat.st_mode & ~S_IFMT) != perms) {
+            sb.append("\nExpected permissions: ");
+            sb.append(Integer.toOctalString(perms));
+            sb.append("\nGot permissions: ");
+            sb.append(Integer.toOctalString(stat.st_mode & ~S_IFMT));
+        }
+
+        if (sb.length() > 0) {
+            throw new AssertionError(reason + sb.toString());
+        }
+    }
+
+    private static void assertStartsWith(String prefix, String actual) {
+        assertStartsWith("", prefix, actual);
+    }
+
+    private static void assertStartsWith(String description, String prefix, String actual) {
+        if (!actual.startsWith(prefix)) {
+            StringBuilder sb = new StringBuilder(description);
+            sb.append("\nExpected prefix: ");
+            sb.append(prefix);
+            sb.append("\n     got: ");
+            sb.append(actual);
+            sb.append('\n');
+            throw new AssertionError(sb.toString());
+        }
+    }
+
     private void assertNotInstalled(String pkgName) {
         try {
             ApplicationInfo info = getPm().getApplicationInfo(pkgName, 0);
@@ -820,22 +891,51 @@
                 | PackageManager.INSTALL_EXTERNAL);
     }
 
-    /* -------------- Delete tests ---*/
+    /* -------------- Delete tests --- */
     private static class DeleteObserver extends IPackageDeleteObserver.Stub {
+        private CountDownLatch mLatch = new CountDownLatch(1);
 
-        public boolean succeeded;
-        private boolean doneFlag = false;
+        private int mReturnCode;
 
-        public boolean isDone() {
-            return doneFlag;
+        private final String mPackageName;
+
+        private String mObservedPackage;
+
+        public DeleteObserver(String packageName) {
+            mPackageName = packageName;
+        }
+
+        public boolean isSuccessful() {
+            return mReturnCode == PackageManager.DELETE_SUCCEEDED;
         }
 
         public void packageDeleted(String packageName, int returnCode) throws RemoteException {
-            synchronized(this) {
-                this.succeeded = returnCode == PackageManager.DELETE_SUCCEEDED;
-                doneFlag = true;
-                notifyAll();
+            mObservedPackage = packageName;
+
+            mReturnCode = returnCode;
+
+            mLatch.countDown();
+        }
+
+        public void waitForCompletion(long timeoutMillis) {
+            final long deadline = SystemClock.uptimeMillis() + timeoutMillis;
+
+            long waitTime = timeoutMillis;
+            while (waitTime > 0) {
+                try {
+                    boolean done = mLatch.await(waitTime, TimeUnit.MILLISECONDS);
+                    if (done) {
+                        assertEquals(mPackageName, mObservedPackage);
+                        return;
+                    }
+                } catch (InterruptedException e) {
+                    // TODO Auto-generated catch block
+                    e.printStackTrace();
+                }
+                waitTime = deadline - SystemClock.uptimeMillis();
             }
+
+            throw new AssertionError("Timeout waiting for package deletion");
         }
     }
 
@@ -863,41 +963,40 @@
         }
     }
 
-    public boolean invokeDeletePackage(final String pkgName, int flags,
-            GenericReceiver receiver) throws Exception {
-        DeleteObserver observer = new DeleteObserver();
-        final boolean received = false;
+    public boolean invokeDeletePackage(final String pkgName, int flags, GenericReceiver receiver)
+            throws Exception {
+        ApplicationInfo info = getPm().getApplicationInfo(pkgName,
+                PackageManager.GET_UNINSTALLED_PACKAGES);
+
         mContext.registerReceiver(receiver, receiver.filter);
         try {
-            // Wait on observer
-            synchronized(observer) {
-                synchronized (receiver) {
-                    getPm().deletePackage(pkgName, observer, flags);
-                    long waitTime = 0;
-                    while((!observer.isDone()) && (waitTime < MAX_WAIT_TIME) ) {
-                        observer.wait(WAIT_TIME_INCR);
-                        waitTime += WAIT_TIME_INCR;
-                    }
-                    if(!observer.isDone()) {
-                        throw new Exception("Timed out waiting for packageInstalled callback");
-                    }
-                    // Verify we received the broadcast
-                    waitTime = 0;
-                    while((!receiver.isDone()) && (waitTime < MAX_WAIT_TIME) ) {
-                        receiver.wait(WAIT_TIME_INCR);
-                        waitTime += WAIT_TIME_INCR;
-                    }
-                    if(!receiver.isDone()) {
-                        throw new Exception("Timed out waiting for PACKAGE_REMOVED notification");
-                    }
-                    return receiver.received;
-                }
+            DeleteObserver observer = new DeleteObserver(pkgName);
+
+            getPm().deletePackage(pkgName, observer, flags);
+            observer.waitForCompletion(MAX_WAIT_TIME);
+
+            assertUninstalled(info);
+
+            // Verify we received the broadcast
+            long waitTime = 0;
+            while ((!receiver.isDone()) && (waitTime < MAX_WAIT_TIME)) {
+                receiver.wait(WAIT_TIME_INCR);
+                waitTime += WAIT_TIME_INCR;
             }
+            if (!receiver.isDone()) {
+                throw new Exception("Timed out waiting for PACKAGE_REMOVED notification");
+            }
+            return receiver.received;
         } finally {
             mContext.unregisterReceiver(receiver);
         }
     }
 
+    private static void assertUninstalled(ApplicationInfo info) throws Exception {
+        File nativeLibraryFile = new File(info.nativeLibraryDir);
+        assertFalse("Native library directory should be erased", nativeLibraryFile.exists());
+    }
+
     public void deleteFromRawResource(int iFlags, int dFlags) throws Exception {
         InstallParams ip = sampleInstallFromRawResource(iFlags, false);
         boolean retainData = ((dFlags & PackageManager.DELETE_KEEP_DATA) != 0);
@@ -1212,11 +1311,29 @@
             return;
         }
         Runtime.getRuntime().gc();
-        Log.i(TAG, "Deleting package : " + ip.pkg.packageName);
-        getPm().deletePackage(ip.pkg.packageName, null, 0);
-        File outFile = new File(ip.pkg.mScanPath);
-        if (outFile != null && outFile.exists()) {
-            outFile.delete();
+
+        final String packageName = ip.pkg.packageName;
+        Log.i(TAG, "Deleting package : " + packageName);
+
+        ApplicationInfo info = null;
+        try {
+            info = getPm().getApplicationInfo(packageName, PackageManager.GET_UNINSTALLED_PACKAGES);
+        } catch (NameNotFoundException ignored) {
+        }
+
+        DeleteObserver observer = new DeleteObserver(packageName);
+        getPm().deletePackage(packageName, observer, 0);
+        observer.waitForCompletion(MAX_WAIT_TIME);
+
+        try {
+            if (info != null) {
+                assertUninstalled(info);
+            }
+        } finally {
+            File outFile = new File(ip.pkg.mScanPath);
+            if (outFile != null && outFile.exists()) {
+                outFile.delete();
+            }
         }
     }
 
@@ -1230,7 +1347,10 @@
                     PackageManager.GET_UNINSTALLED_PACKAGES);
 
             if (info != null) {
-                getPm().deletePackage(pkgName, null, 0);
+                DeleteObserver observer = new DeleteObserver(pkgName);
+                getPm().deletePackage(pkgName, observer, 0);
+                observer.waitForCompletion(MAX_WAIT_TIME);
+                assertUninstalled(info);
             }
         } catch (NameNotFoundException e) {
         }
@@ -1587,16 +1707,16 @@
                 if ((moveFlags & PackageManager.MOVE_INTERNAL) != 0) {
                     assertTrue("ApplicationInfo.FLAG_EXTERNAL_STORAGE flag should NOT be set",
                             (info.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) == 0);
-                    assertTrue("ApplicationInfo.nativeLibraryDir should start with " + info.dataDir,
-                            info.nativeLibraryDir.startsWith(info.dataDir));
-                } else if ((moveFlags & PackageManager.MOVE_EXTERNAL_MEDIA) != 0){
+                    assertStartsWith("Native library dir should be in dataDir",
+                            info.dataDir, info.nativeLibraryDir);
+                } else if ((moveFlags & PackageManager.MOVE_EXTERNAL_MEDIA) != 0) {
                     assertTrue("ApplicationInfo.FLAG_EXTERNAL_STORAGE flag should be set",
                             (info.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0);
-                    assertTrue("ApplicationInfo.nativeLibraryDir should start with " + SECURE_CONTAINERS_PREFIX,
-                            info.nativeLibraryDir.startsWith(SECURE_CONTAINERS_PREFIX));
+                    assertStartsWith("Native library dir should point to ASEC",
+                            SECURE_CONTAINERS_PREFIX, info.nativeLibraryDir);
                     final File nativeLibSymLink = new File(info.dataDir, "lib");
-                    assertTrue("The data directory should have a 'lib' symlink that points to the ASEC container",
-                            nativeLibSymLink.getCanonicalPath().startsWith(SECURE_CONTAINERS_PREFIX));
+                    assertStartsWith("The data directory should have a 'lib' symlink that points to the ASEC container",
+                            SECURE_CONTAINERS_PREFIX, nativeLibSymLink.getCanonicalPath());
                 }
             }
         } catch (NameNotFoundException e) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java
index e9dd70a..f374c11 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java
@@ -22,18 +22,15 @@
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.CursorLoader;
-import android.content.DialogInterface;
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.Loader;
 import android.content.res.Resources;
 import android.database.Cursor;
-import android.database.DataSetObserver;
 import android.graphics.drawable.ClipDrawable;
 import android.hardware.display.DisplayManager;
 import android.hardware.display.WifiDisplay;
 import android.hardware.display.WifiDisplayStatus;
-import android.hardware.input.KeyboardLayout;
 import android.net.Uri;
 import android.provider.ContactsContract;
 import android.provider.Settings;
@@ -44,12 +41,8 @@
 import android.widget.AdapterView;
 import android.widget.ArrayAdapter;
 import android.widget.Button;
-import android.widget.CheckedTextView;
 import android.widget.ListView;
-import android.widget.RadioButton;
 import android.widget.TextView;
-import android.widget.Toast;
-import android.widget.ListAdapter;
 
 import java.util.ArrayList;
 import java.util.Comparator;
@@ -411,7 +404,7 @@
                     @Override
                     public void onLoadComplete(Loader<Cursor> loader,
                             Cursor cursor) {
-                        if (cursor.moveToFirst()) {
+                        if (cursor != null && cursor.moveToFirst()) {
                             String name = cursor.getString(0); // DISPLAY_NAME
                             mModel.setUserTileInfo(name);
                             /*
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSelectorView.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSelectorView.java
index 95772af..7554236 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSelectorView.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSelectorView.java
@@ -142,7 +142,9 @@
     protected void launchCamera() {
         if (mLockPatternUtils.isSecure()) {
             // Launch the secure version of the camera
-            launchActivity(new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE), true);
+            Intent intent = new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE);
+            intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
+            launchActivity(intent, true);
         } else {
             // Launch the normal camera
             launchActivity(new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA), false);
@@ -262,7 +264,7 @@
      * See {@link WindowManager#FLAG_SHOW_WHEN_LOCKED}
      */
     private void launchActivity(final Intent intent, boolean showsWhileLocked) {
-        intent.setFlags(
+        intent.addFlags(
                 Intent.FLAG_ACTIVITY_NEW_TASK
                 | Intent.FLAG_ACTIVITY_SINGLE_TOP
                 | Intent.FLAG_ACTIVITY_CLEAR_TOP);
diff --git a/services/java/com/android/server/am/ActiveServices.java b/services/java/com/android/server/am/ActiveServices.java
index 7144808..2975880 100644
--- a/services/java/com/android/server/am/ActiveServices.java
+++ b/services/java/com/android/server/am/ActiveServices.java
@@ -1551,8 +1551,12 @@
                 }
             }
         } else {
-            didSomething = collectForceStopServicesLocked(name, userId, evenPersistent,
-                    doit, mServiceMap.mServicesByNamePerUser.get(userId), services);
+            HashMap<ComponentName, ServiceRecord> items
+                    = mServiceMap.mServicesByNamePerUser.get(userId);
+            if (items != null) {
+                didSomething = collectForceStopServicesLocked(name, userId, evenPersistent,
+                        doit, items, services);
+            }
         }
 
         int N = services.size();
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index ca45946..0b2d769 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -546,7 +546,7 @@
      */
     final ArrayList mCancelledThumbnails = new ArrayList();
 
-    final ProviderMap mProviderMap = new ProviderMap();
+    final ProviderMap mProviderMap;
 
     /**
      * List of content providers who have clients waiting for them.  The
@@ -1511,6 +1511,7 @@
         mBroadcastQueues[1] = mBgBroadcastQueue;
 
         mServices = new ActiveServices(this);
+        mProviderMap = new ProviderMap(this);
 
         File dataDir = Environment.getDataDirectory();
         File systemDir = new File(dataDir, "system");
@@ -1792,7 +1793,7 @@
             // Also don't let it kick out the first few "real" hidden processes.
             skipTop = ProcessList.MIN_HIDDEN_APPS;
         }
-        
+
         while (i >= 0) {
             ProcessRecord p = mLruProcesses.get(i);
             // If this app shouldn't be in front of the first N background
@@ -2680,7 +2681,7 @@
             }
             final long origId = Binder.clearCallingIdentity();
             boolean res = mMainStack.requestFinishActivityLocked(token, resultCode,
-                    resultData, "app-request");
+                    resultData, "app-request", true);
             Binder.restoreCallingIdentity(origId);
             return res;
         }
@@ -2710,7 +2711,7 @@
                     int index = mMainStack.indexOfTokenLocked(r.appToken);
                     if (index >= 0) {
                         mMainStack.finishActivityLocked(r, index, Activity.RESULT_CANCELED,
-                                null, "finish-heavy");
+                                null, "finish-heavy", true);
                     }
                 }
             }
@@ -3627,7 +3628,7 @@
             ActivityRecord r = (ActivityRecord)mMainStack.mHistory.get(i);
             if ((r.info.flags&ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS) != 0) {
                 r.stack.finishActivityLocked(r, i,
-                        Activity.RESULT_CANCELED, null, "close-sys");
+                        Activity.RESULT_CANCELED, null, "close-sys", true);
             }
         }
 
@@ -6972,7 +6973,7 @@
             if (count > 1) {
                 final long origId = Binder.clearCallingIdentity();
                 mMainStack.finishActivityLocked((ActivityRecord)mMainStack.mHistory.get(count-1),
-                        count-1, Activity.RESULT_CANCELED, null, "unhandled-back");
+                        count-1, Activity.RESULT_CANCELED, null, "unhandled-back", true);
                 Binder.restoreCallingIdentity(origId);
             }
         }
@@ -7891,7 +7892,8 @@
                 if (r.app == app) {
                     Slog.w(TAG, "  Force finishing activity "
                         + r.intent.getComponent().flattenToShortString());
-                    r.stack.finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "crashed");
+                    r.stack.finishActivityLocked(r, i, Activity.RESULT_CANCELED,
+                            null, "crashed", false);
                 }
             }
             if (!app.persistent) {
@@ -7926,7 +7928,7 @@
                         + r.intent.getComponent().flattenToShortString());
                 int index = mMainStack.indexOfActivityLocked(r);
                 r.stack.finishActivityLocked(r, index,
-                        Activity.RESULT_CANCELED, null, "crashed");
+                        Activity.RESULT_CANCELED, null, "crashed", false);
                 // Also terminate any activities below it that aren't yet
                 // stopped, to avoid a situation where one will get
                 // re-start our crashing activity once it gets resumed again.
@@ -7940,7 +7942,7 @@
                             Slog.w(TAG, "  Force finishing activity "
                                     + r.intent.getComponent().flattenToShortString());
                             r.stack.finishActivityLocked(r, index,
-                                    Activity.RESULT_CANCELED, null, "crashed");
+                                    Activity.RESULT_CANCELED, null, "crashed", false);
                         }
                     }
                 }
@@ -12305,7 +12307,7 @@
             for (int i = start; i > finishTo; i--) {
                 ActivityRecord r = history.get(i);
                 mMainStack.requestFinishActivityLocked(r.appToken, resultCode, resultData,
-                        "navigate-up");
+                        "navigate-up", true);
                 // Only return the supplied result for the first activity finished
                 resultCode = Activity.RESULT_CANCELED;
                 resultData = null;
@@ -12331,7 +12333,7 @@
                         foundParentInTask = false;
                     }
                     mMainStack.requestFinishActivityLocked(parent.appToken, resultCode,
-                            resultData, "navigate-up");
+                            resultData, "navigate-up", true);
                 }
             }
             Binder.restoreCallingIdentity(origId);
diff --git a/services/java/com/android/server/am/ActivityRecord.java b/services/java/com/android/server/am/ActivityRecord.java
index c70650d..009fb5d 100644
--- a/services/java/com/android/server/am/ActivityRecord.java
+++ b/services/java/com/android/server/am/ActivityRecord.java
@@ -333,7 +333,6 @@
         state = ActivityState.INITIALIZING;
         frontOfTask = false;
         launchFailed = false;
-        haveState = false;
         stopped = false;
         delayedResume = false;
         finishing = false;
@@ -347,6 +346,11 @@
         idle = false;
         hasBeenLaunched = false;
 
+        // This starts out true, since the initial state of an activity
+        // is that we have everything, and we shouldn't never consider it
+        // lacking in state to be removed if it dies.
+        haveState = true;
+
         if (aInfo != null) {
             if (aInfo.targetActivity == null
                     || aInfo.launchMode == ActivityInfo.LAUNCH_MULTIPLE
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index 895b52a..bc835b6 100755
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -725,7 +725,7 @@
                       + ", giving up", e);
                 mService.appDiedLocked(app, app.pid, app.thread);
                 requestFinishActivityLocked(r.appToken, Activity.RESULT_CANCELED, null,
-                        "2nd-crash");
+                        "2nd-crash", false);
                 return false;
             }
 
@@ -1092,7 +1092,7 @@
         if (prev != null) {
             if (prev.finishing) {
                 if (DEBUG_PAUSE) Slog.v(TAG, "Executing finish of activity: " + prev);
-                prev = finishCurrentActivityLocked(prev, FINISH_AFTER_VISIBLE);
+                prev = finishCurrentActivityLocked(prev, FINISH_AFTER_VISIBLE, false);
             } else if (prev.app != null) {
                 if (DEBUG_PAUSE) Slog.v(TAG, "Enqueueing pending stop: " + prev);
                 if (prev.waitingVisible) {
@@ -1504,7 +1504,7 @@
                     Slog.d(TAG, "no-history finish of " + last + " on new resume");
                 }
                 requestFinishActivityLocked(last.appToken, Activity.RESULT_CANCELED, null,
-                        "no-history");
+                        "no-history", false);
             }
         }
 
@@ -1726,7 +1726,7 @@
                 // activity and try the next one.
                 Slog.w(TAG, "Exception thrown during resume of " + next, e);
                 requestFinishActivityLocked(next.appToken, Activity.RESULT_CANCELED, null,
-                        "resume-exception");
+                        "resume-exception", true);
                 return true;
             }
 
@@ -2080,7 +2080,7 @@
                                 continue;
                             }
                             if (finishActivityLocked(p, srcPos,
-                                    Activity.RESULT_CANCELED, null, "reset")) {
+                                    Activity.RESULT_CANCELED, null, "reset", false)) {
                                 replyChainEnd--;
                                 srcPos--;
                             }
@@ -2143,7 +2143,7 @@
                             continue;
                         }
                         if (finishActivityLocked(p, srcPos,
-                                Activity.RESULT_CANCELED, null, "reset")) {
+                                Activity.RESULT_CANCELED, null, "reset", false)) {
                             taskTopI--;
                             lastReparentPos--;
                             replyChainEnd--;
@@ -2200,7 +2200,7 @@
                             }
                             if (p.intent.getComponent().equals(target.intent.getComponent())) {
                                 if (finishActivityLocked(p, j,
-                                        Activity.RESULT_CANCELED, null, "replace")) {
+                                        Activity.RESULT_CANCELED, null, "replace", false)) {
                                     taskTopI--;
                                     lastReparentPos--;
                                 }
@@ -2270,7 +2270,7 @@
                         continue;
                     }
                     if (finishActivityLocked(r, i, Activity.RESULT_CANCELED,
-                            null, "clear")) {
+                            null, "clear", false)) {
                         i--;
                     }
                 }
@@ -2284,7 +2284,7 @@
                         int index = indexOfTokenLocked(ret.appToken);
                         if (index >= 0) {
                             finishActivityLocked(ret, index, Activity.RESULT_CANCELED,
-                                    null, "clear");
+                                    null, "clear", false);
                         }
                         return null;
                     }
@@ -2313,7 +2313,7 @@
                 continue;
             }
             if (!finishActivityLocked(r, i, Activity.RESULT_CANCELED,
-                    null, "clear")) {
+                    null, "clear", false)) {
                 i++;
             }
         }
@@ -2579,6 +2579,7 @@
             mDismissKeyguardOnNextActivity = false;
             mService.mWindowManager.dismissKeyguard();
         }
+        Slog.i(TAG, "DONE STARTING!");
         return err;
     }
   
@@ -3319,7 +3320,7 @@
                         Slog.d(TAG, "no-history finish of " + r);
                     }
                     requestFinishActivityLocked(r.appToken, Activity.RESULT_CANCELED, null,
-                            "no-history");
+                            "no-history", false);
                 } else {
                     if (DEBUG_STATES) Slog.d(TAG, "Not finishing noHistory " + r
                             + " on stop because we're just sleeping");
@@ -3531,7 +3532,7 @@
             ActivityRecord r = (ActivityRecord)stops.get(i);
             synchronized (mService) {
                 if (r.finishing) {
-                    finishCurrentActivityLocked(r, FINISH_IMMEDIATELY);
+                    finishCurrentActivityLocked(r, FINISH_IMMEDIATELY, false);
                 } else {
                     stopActivityLocked(r);
                 }
@@ -3585,7 +3586,7 @@
      * some reason it is being left as-is.
      */
     final boolean requestFinishActivityLocked(IBinder token, int resultCode,
-            Intent resultData, String reason) {
+            Intent resultData, String reason, boolean oomAdj) {
         int index = indexOfTokenLocked(token);
         if (DEBUG_RESULTS || DEBUG_STATES) Slog.v(
                 TAG, "Finishing activity @" + index + ": token=" + token
@@ -3596,7 +3597,7 @@
         }
         ActivityRecord r = mHistory.get(index);
 
-        finishActivityLocked(r, index, resultCode, resultData, reason);
+        finishActivityLocked(r, index, resultCode, resultData, reason, oomAdj);
         return true;
     }
 
@@ -3613,10 +3614,11 @@
                 if ((r.resultWho == null && resultWho == null) ||
                     (r.resultWho != null && r.resultWho.equals(resultWho))) {
                     finishActivityLocked(r, i,
-                            Activity.RESULT_CANCELED, null, "request-sub");
+                            Activity.RESULT_CANCELED, null, "request-sub", false);
                 }
             }
         }
+        mService.updateOomAdjLocked();
     }
 
     final boolean finishActivityAffinityLocked(IBinder token) {
@@ -3639,7 +3641,8 @@
             if (cur.taskAffinity != null && !cur.taskAffinity.equals(r.taskAffinity)) {
                 break;
             }
-            finishActivityLocked(cur, index, Activity.RESULT_CANCELED, null, "request-affinity");
+            finishActivityLocked(cur, index, Activity.RESULT_CANCELED, null,
+                    "request-affinity", true);
             index--;
         }
         return true;
@@ -3677,16 +3680,16 @@
      * list, or false if it is still in the list and will be removed later.
      */
     final boolean finishActivityLocked(ActivityRecord r, int index,
-            int resultCode, Intent resultData, String reason) {
-        return finishActivityLocked(r, index, resultCode, resultData, reason, false);
+            int resultCode, Intent resultData, String reason, boolean oomAdj) {
+        return finishActivityLocked(r, index, resultCode, resultData, reason, false, oomAdj);
     }
 
     /**
      * @return Returns true if this activity has been removed from the history
      * list, or false if it is still in the list and will be removed later.
      */
-    final boolean finishActivityLocked(ActivityRecord r, int index,
-            int resultCode, Intent resultData, String reason, boolean immediate) {
+    final boolean finishActivityLocked(ActivityRecord r, int index, int resultCode,
+            Intent resultData, String reason, boolean immediate, boolean oomAdj) {
         if (r.finishing) {
             Slog.w(TAG, "Duplicate finish request for " + r);
             return false;
@@ -3730,7 +3733,7 @@
 
         if (immediate) {
             return finishCurrentActivityLocked(r, index,
-                    FINISH_IMMEDIATELY) == null;
+                    FINISH_IMMEDIATELY, oomAdj) == null;
         } else if (mResumedActivity == r) {
             boolean endTask = index <= 0
                     || (mHistory.get(index-1)).task != r.task;
@@ -3754,7 +3757,7 @@
             // it is done pausing; else we can just directly finish it here.
             if (DEBUG_PAUSE) Slog.v(TAG, "Finish not pausing: " + r);
             return finishCurrentActivityLocked(r, index,
-                    FINISH_AFTER_PAUSE) == null;
+                    FINISH_AFTER_PAUSE, oomAdj) == null;
         } else {
             if (DEBUG_PAUSE) Slog.v(TAG, "Finish waiting for pause of: " + r);
         }
@@ -3767,17 +3770,17 @@
     private static final int FINISH_AFTER_VISIBLE = 2;
 
     private final ActivityRecord finishCurrentActivityLocked(ActivityRecord r,
-            int mode) {
+            int mode, boolean oomAdj) {
         final int index = indexOfActivityLocked(r);
         if (index < 0) {
             return null;
         }
 
-        return finishCurrentActivityLocked(r, index, mode);
+        return finishCurrentActivityLocked(r, index, mode, oomAdj);
     }
 
     private final ActivityRecord finishCurrentActivityLocked(ActivityRecord r,
-            int index, int mode) {
+            int index, int mode, boolean oomAdj) {
         // First things first: if this activity is currently visible,
         // and the resumed activity is not yet visible, then hold off on
         // finishing until the resumed one becomes visible.
@@ -3796,7 +3799,9 @@
             if (DEBUG_STATES) Slog.v(TAG, "Moving to STOPPING: " + r
                     + " (finish requested)");
             r.state = ActivityState.STOPPING;
-            mService.updateOomAdjLocked();
+            if (oomAdj) {
+                mService.updateOomAdjLocked();
+            }
             return r;
         }
 
@@ -3816,7 +3821,8 @@
                 || prevState == ActivityState.INITIALIZING) {
             // If this activity is already stopped, we can just finish
             // it right now.
-            boolean activityRemoved = destroyActivityLocked(r, true, true, "finish-imm");
+            boolean activityRemoved = destroyActivityLocked(r, true,
+                    oomAdj, "finish-imm");
             if (activityRemoved) {
                 resumeTopActivityLocked(null);
             }
@@ -4008,9 +4014,8 @@
                             ActivityManagerService.CANCEL_HEAVY_NOTIFICATION_MSG);
                 }
                 if (r.app.activities.size() == 0) {
-                    // No longer have activities, so update location in
-                    // LRU list.
-                    mService.updateLruProcessLocked(r.app, oomAdj, false);
+                    // No longer have activities, so update oom adj.
+                    mService.updateOomAdjLocked();
                 }
             }
 
diff --git a/services/java/com/android/server/am/ProviderMap.java b/services/java/com/android/server/am/ProviderMap.java
index 2d7167b..9dbf5f5 100644
--- a/services/java/com/android/server/am/ProviderMap.java
+++ b/services/java/com/android/server/am/ProviderMap.java
@@ -18,7 +18,6 @@
 
 import android.content.ComponentName;
 import android.os.Binder;
-import android.os.Process;
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.util.Slog;
@@ -31,8 +30,6 @@
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
 
 /**
  * Keeps track of content providers by authority (name) and class. It separates the mapping by
@@ -44,6 +41,8 @@
 
     private static final boolean DBG = false;
 
+    private final ActivityManagerService mAm;
+
     private final HashMap<String, ContentProviderRecord> mSingletonByName
             = new HashMap<String, ContentProviderRecord>();
     private final HashMap<ComponentName, ContentProviderRecord> mSingletonByClass
@@ -54,6 +53,10 @@
     private final SparseArray<HashMap<ComponentName, ContentProviderRecord>> mProvidersByClassPerUser
             = new SparseArray<HashMap<ComponentName, ContentProviderRecord>>();
 
+    ProviderMap(ActivityManagerService am) {
+        mAm = am;
+    }
+
     ContentProviderRecord getProviderByName(String name) {
         return getProviderByName(name, -1);
     }
@@ -217,8 +220,12 @@
                 }
             }
         } else {
-            didSomething |= collectForceStopProvidersLocked(name, appId, doit, evenPersistent,
-                    userId, getProvidersByClass(userId), result);
+            HashMap<ComponentName, ContentProviderRecord> items
+                    = getProvidersByClass(userId);
+            if (items != null) {
+                didSomething |= collectForceStopProvidersLocked(name, appId, doit,
+                        evenPersistent, userId, items, result);
+            }
         }
         return didSomething;
     }
@@ -279,30 +286,33 @@
 
     protected boolean dumpProvider(FileDescriptor fd, PrintWriter pw, String name, String[] args,
             int opti, boolean dumpAll) {
+        ArrayList<ContentProviderRecord> allProviders = new ArrayList<ContentProviderRecord>();
         ArrayList<ContentProviderRecord> providers = new ArrayList<ContentProviderRecord>();
 
-        if ("all".equals(name)) {
-            synchronized (this) {
-                for (ContentProviderRecord r1 : getProvidersByClass(-1).values()) {
-                    providers.add(r1);
-                }
-            }
-        } else {
-            ComponentName componentName = name != null
-                    ? ComponentName.unflattenFromString(name) : null;
-            int objectId = 0;
-            if (componentName == null) {
-                // Not a '/' separated full component name; maybe an object ID?
-                try {
-                    objectId = Integer.parseInt(name, 16);
-                    name = null;
-                    componentName = null;
-                } catch (RuntimeException e) {
-                }
+        synchronized (mAm) {
+            allProviders.addAll(mSingletonByClass.values());
+            for (int i=0; i<mProvidersByClassPerUser.size(); i++) {
+                allProviders.addAll(mProvidersByClassPerUser.valueAt(i).values());
             }
 
-            synchronized (this) {
-                for (ContentProviderRecord r1 : getProvidersByClass(-1).values()) {
+            if ("all".equals(name)) {
+                providers.addAll(allProviders);
+            } else {
+                ComponentName componentName = name != null
+                        ? ComponentName.unflattenFromString(name) : null;
+                int objectId = 0;
+                if (componentName == null) {
+                    // Not a '/' separated full component name; maybe an object ID?
+                    try {
+                        objectId = Integer.parseInt(name, 16);
+                        name = null;
+                        componentName = null;
+                    } catch (RuntimeException e) {
+                    }
+                }
+
+                for (int i=0; i<allProviders.size(); i++) {
+                    ContentProviderRecord r1 = allProviders.get(i);
                     if (componentName != null) {
                         if (r1.name.equals(componentName)) {
                             providers.add(r1);
@@ -340,7 +350,7 @@
     private void dumpProvider(String prefix, FileDescriptor fd, PrintWriter pw,
             final ContentProviderRecord r, String[] args, boolean dumpAll) {
         String innerPrefix = prefix + "  ";
-        synchronized (this) {
+        synchronized (mAm) {
             pw.print(prefix); pw.print("PROVIDER ");
                     pw.print(r);
                     pw.print(" pid=");
diff --git a/services/java/com/android/server/display/DisplayManagerService.java b/services/java/com/android/server/display/DisplayManagerService.java
index e11d454..39f2418 100644
--- a/services/java/com/android/server/display/DisplayManagerService.java
+++ b/services/java/com/android/server/display/DisplayManagerService.java
@@ -352,7 +352,9 @@
         final long token = Binder.clearCallingIdentity();
         try {
             synchronized (mSyncRoot) {
-                mWifiDisplayAdapter.requestScanLocked();
+                if (mWifiDisplayAdapter != null) {
+                    mWifiDisplayAdapter.requestScanLocked();
+                }
             }
         } finally {
             Binder.restoreCallingIdentity(token);
@@ -372,7 +374,9 @@
         final long token = Binder.clearCallingIdentity();
         try {
             synchronized (mSyncRoot) {
-                mWifiDisplayAdapter.requestConnectLocked(address);
+                if (mWifiDisplayAdapter != null) {
+                    mWifiDisplayAdapter.requestConnectLocked(address);
+                }
             }
         } finally {
             Binder.restoreCallingIdentity(token);
@@ -389,7 +393,9 @@
         final long token = Binder.clearCallingIdentity();
         try {
             synchronized (mSyncRoot) {
-                mWifiDisplayAdapter.requestDisconnectLocked();
+                if (mWifiDisplayAdapter != null) {
+                    mWifiDisplayAdapter.requestDisconnectLocked();
+                }
             }
         } finally {
             Binder.restoreCallingIdentity(token);
@@ -406,7 +412,11 @@
         final long token = Binder.clearCallingIdentity();
         try {
             synchronized (mSyncRoot) {
-                return mWifiDisplayAdapter.getWifiDisplayStatusLocked();
+                if (mWifiDisplayAdapter != null) {
+                    return mWifiDisplayAdapter.getWifiDisplayStatusLocked();
+                } else {
+                    return new WifiDisplayStatus();
+                }
             }
         } finally {
             Binder.restoreCallingIdentity(token);
diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java
index d0f2ed1..4bb6e38 100644
--- a/services/java/com/android/server/pm/PackageManagerService.java
+++ b/services/java/com/android/server/pm/PackageManagerService.java
@@ -8118,10 +8118,7 @@
 
         // Delete application code and resources
         if (deleteCodeAndResources) {
-            // TODO can pick up from PackageSettings as well
-            int installFlags = isExternal(ps) ? PackageManager.INSTALL_EXTERNAL : 0;
-            installFlags |= isForwardLocked(ps) ? PackageManager.INSTALL_FORWARD_LOCK : 0;
-            outInfo.args = createInstallArgs(installFlags, ps.codePathString,
+            outInfo.args = createInstallArgs(packageFlagsToInstallFlags(ps), ps.codePathString,
                     ps.resourcePathString, ps.nativeLibraryPathString);
         }
         return true;
diff --git a/services/java/com/android/server/pm/Settings.java b/services/java/com/android/server/pm/Settings.java
index b85353c..b075da3 100644
--- a/services/java/com/android/server/pm/Settings.java
+++ b/services/java/com/android/server/pm/Settings.java
@@ -566,6 +566,10 @@
         if (p.signatures.mSignatures == null) {
             p.signatures.assignSignatures(pkg.mSignatures);
         }
+        // Update flags if needed.
+        if (pkg.applicationInfo.flags != p.pkgFlags) {
+            p.pkgFlags = pkg.applicationInfo.flags;
+        }
         // If this app defines a shared user id initialize
         // the shared user signatures as well.
         if (p.sharedUser != null && p.sharedUser.signatures.mSignatures == null) {
@@ -2616,10 +2620,10 @@
                 pw.print("    installerPackageName="); pw.println(ps.installerPackageName);
             }
             pw.print("    signatures="); pw.println(ps.signatures);
-            pw.print("    permissionsFixed="); pw.print(ps.permissionsFixed);
-            pw.print(" haveGids="); pw.println(ps.haveGids);
-            pw.print("    pkgFlags=0x"); pw.print(Integer.toHexString(ps.pkgFlags));
-            pw.print(" installStatus="); pw.println(ps.installStatus);
+            pw.print("    permissionsFixed="); pw.println(ps.permissionsFixed);
+            pw.print("    haveGids="); pw.println(ps.haveGids);
+            pw.print("    pkgFlags="); printFlags(pw, ps.pkgFlags, FLAG_DUMP_SPEC);
+            pw.print("    installStatus="); pw.println(ps.installStatus);
             for (UserInfo user : users) {
                 pw.print("    User "); pw.print(user.id); pw.print(": ");
                 pw.print(" installed=");
diff --git a/tools/aapt/Android.mk b/tools/aapt/Android.mk
index 482f43e..d9b0681 100644
--- a/tools/aapt/Android.mk
+++ b/tools/aapt/Android.mk
@@ -34,7 +34,6 @@
 endif
 
 
-LOCAL_C_INCLUDES += external/expat/lib
 LOCAL_C_INCLUDES += external/libpng
 LOCAL_C_INCLUDES += external/zlib
 LOCAL_C_INCLUDES += build/libs/host/include
diff --git a/tools/aapt/StringPool.h b/tools/aapt/StringPool.h
index d501008..16050b2 100644
--- a/tools/aapt/StringPool.h
+++ b/tools/aapt/StringPool.h
@@ -21,7 +21,7 @@
 #include <ctype.h>
 #include <errno.h>
 
-#include <expat.h>
+#include <libexpat/expat.h>
 
 using namespace android;
 
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pDevice.java b/wifi/java/android/net/wifi/p2p/WifiP2pDevice.java
index 117af82..863a055 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pDevice.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pDevice.java
@@ -124,7 +124,8 @@
         "name='(.*)' " +
         "config_methods=(0x[0-9a-fA-F]+) " +
         "dev_capab=(0x[0-9a-fA-F]+) " +
-        "group_capab=(0x[0-9a-fA-F]+)"
+        "group_capab=(0x[0-9a-fA-F]+)" +
+        "( wfd_dev_info=0x000006([0-9a-fA-F]{12}))?"
     );
 
     /** 2 token device address pattern
@@ -153,7 +154,7 @@
      * @param string formats supported include
      *  P2P-DEVICE-FOUND fa:7b:7a:42:02:13 p2p_dev_addr=fa:7b:7a:42:02:13
      *  pri_dev_type=1-0050F204-1 name='p2p-TEST1' config_methods=0x188 dev_capab=0x27
-     *  group_capab=0x0
+     *  group_capab=0x0 wfd_dev_info=000006015d022a0032
      *
      *  P2P-DEVICE-LOST p2p_dev_addr=fa:7b:7a:42:02:13
      *
@@ -205,6 +206,12 @@
                 wpsConfigMethodsSupported = parseHex(match.group(6));
                 deviceCapability = parseHex(match.group(7));
                 groupCapability = parseHex(match.group(8));
+                if (match.group(9) != null) {
+                    String str = match.group(10);
+                    wfdInfo = new WifiP2pWfdInfo(parseHex(str.substring(0,4)),
+                            parseHex(str.substring(4,8)),
+                            parseHex(str.substring(8,12)));
+                }
                 break;
         }
 
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pDeviceList.java b/wifi/java/android/net/wifi/p2p/WifiP2pDeviceList.java
index 48cdbc2..2093bda 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pDeviceList.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pDeviceList.java
@@ -35,10 +35,9 @@
  */
 public class WifiP2pDeviceList implements Parcelable {
 
-    private HashMap<String, WifiP2pDevice> mDevices;
+    private final HashMap<String, WifiP2pDevice> mDevices = new HashMap<String, WifiP2pDevice>();
 
     public WifiP2pDeviceList() {
-        mDevices = new HashMap<String, WifiP2pDevice>();
     }
 
     /** copy constructor */
@@ -52,7 +51,6 @@
 
     /** @hide */
     public WifiP2pDeviceList(ArrayList<WifiP2pDevice> devices) {
-        mDevices = new HashMap<String, WifiP2pDevice>();
         for (WifiP2pDevice device : devices) {
             if (device.deviceAddress != null) {
                 mDevices.put(device.deviceAddress, device);
@@ -78,6 +76,7 @@
             d.wpsConfigMethodsSupported = device.wpsConfigMethodsSupported;
             d.deviceCapability = device.deviceCapability;
             d.groupCapability = device.groupCapability;
+            d.wfdInfo = device.wfdInfo;
             return;
         }
         //Not found, add a new one
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pGroupList.java b/wifi/java/android/net/wifi/p2p/WifiP2pGroupList.java
index 3459a5a..98f0972 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pGroupList.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pGroupList.java
@@ -16,6 +16,7 @@
 package android.net.wifi.p2p;
 
 import java.util.Collection;
+import java.util.Map;
 
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -32,8 +33,9 @@
 
     private static final int CREDENTIAL_MAX_NUM             =   32;
 
-    private LruCache<Integer, WifiP2pGroup> mGroups;
-    private GroupDeleteListener mListener;
+    private final LruCache<Integer, WifiP2pGroup> mGroups;
+    private final GroupDeleteListener mListener;
+
     private boolean isClearCalled = false;
 
     public interface GroupDeleteListener {
@@ -41,10 +43,10 @@
     }
 
     WifiP2pGroupList() {
-        this(null);
+        this(null, null);
     }
 
-    WifiP2pGroupList(GroupDeleteListener listener) {
+    WifiP2pGroupList(WifiP2pGroupList source, GroupDeleteListener listener) {
         mListener = listener;
         mGroups = new LruCache<Integer, WifiP2pGroup>(CREDENTIAL_MAX_NUM) {
             @Override
@@ -55,6 +57,12 @@
                 }
             }
         };
+
+        if (source != null) {
+            for (Map.Entry<Integer, WifiP2pGroup> item : source.mGroups.snapshot().entrySet()) {
+                mGroups.put(item.getKey(), item.getValue());
+            }
+        }
     }
 
     /**
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pService.java b/wifi/java/android/net/wifi/p2p/WifiP2pService.java
index a6770bd..3575d97 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pService.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pService.java
@@ -359,8 +359,8 @@
         private WifiNative mWifiNative = new WifiNative(mInterface);
         private WifiMonitor mWifiMonitor = new WifiMonitor(this, mWifiNative);
 
-        private WifiP2pDeviceList mPeers = new WifiP2pDeviceList();
-        private WifiP2pGroupList mGroups = new WifiP2pGroupList(
+        private final WifiP2pDeviceList mPeers = new WifiP2pDeviceList();
+        private final WifiP2pGroupList mGroups = new WifiP2pGroupList(null,
                 new GroupDeleteListener() {
             @Override
             public void onDeleteGroup(int netId) {
@@ -370,7 +370,7 @@
                 sendP2pPersistentGroupsChangedBroadcast();
             }
         });
-        private WifiP2pInfo mWifiP2pInfo = new WifiP2pInfo();
+        private final WifiP2pInfo mWifiP2pInfo = new WifiP2pInfo();
         private WifiP2pGroup mGroup;
 
         // Saved WifiP2pConfig for a peer connection
@@ -501,17 +501,20 @@
                             WifiP2pManager.BUSY);
                     break;
                 case WifiP2pManager.REQUEST_PEERS:
-                    replyToMessage(message, WifiP2pManager.RESPONSE_PEERS, mPeers);
+                    replyToMessage(message, WifiP2pManager.RESPONSE_PEERS,
+                            new WifiP2pDeviceList(mPeers));
                     break;
                 case WifiP2pManager.REQUEST_CONNECTION_INFO:
-                    replyToMessage(message, WifiP2pManager.RESPONSE_CONNECTION_INFO, mWifiP2pInfo);
+                    replyToMessage(message, WifiP2pManager.RESPONSE_CONNECTION_INFO,
+                            new WifiP2pInfo(mWifiP2pInfo));
                     break;
                 case WifiP2pManager.REQUEST_GROUP_INFO:
-                    replyToMessage(message, WifiP2pManager.RESPONSE_GROUP_INFO, mGroup);
+                    replyToMessage(message, WifiP2pManager.RESPONSE_GROUP_INFO,
+                            mGroup != null ? new WifiP2pGroup(mGroup) : null);
                     break;
                 case WifiP2pManager.REQUEST_PERSISTENT_GROUP_INFO:
                     replyToMessage(message, WifiP2pManager.RESPONSE_PERSISTENT_GROUP_INFO,
-                            mGroups);
+                            new WifiP2pGroupList(mGroups, null));
                     break;
                 case WifiP2pManager.SET_DIALOG_LISTENER:
                     String appPkgName = (String)message.getData().getString(
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pWfdInfo.java b/wifi/java/android/net/wifi/p2p/WifiP2pWfdInfo.java
index 9dd3e4a..b6bbfc4 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pWfdInfo.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pWfdInfo.java
@@ -54,6 +54,13 @@
     public WifiP2pWfdInfo() {
     }
 
+    public WifiP2pWfdInfo(int devInfo, int ctrlPort, int maxTput) {
+        mWfdEnabled = true;
+        mDeviceInfo = devInfo;
+        mCtrlPort = ctrlPort;
+        mMaxThroughput = maxTput;
+    }
+
     public boolean isWfdEnabled() {
         return mWfdEnabled;
     }