Merge "Revert "Check GLES2 support using EGL instead of qemu.gles""
diff --git a/api/system-current.txt b/api/system-current.txt
index 9db70e3..67d16d7 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -20523,6 +20523,7 @@
   public class X509TrustManagerExtensions {
     ctor public X509TrustManagerExtensions(javax.net.ssl.X509TrustManager) throws java.lang.IllegalArgumentException;
     method public java.util.List<java.security.cert.X509Certificate> checkServerTrusted(java.security.cert.X509Certificate[], java.lang.String, java.lang.String) throws java.security.cert.CertificateException;
+    method public boolean isSameTrustConfiguration(java.lang.String, java.lang.String);
     method public boolean isUserAddedCertificate(java.security.cert.X509Certificate);
   }
 
diff --git a/core/java/android/net/http/X509TrustManagerExtensions.java b/core/java/android/net/http/X509TrustManagerExtensions.java
index eb4ceda..25ef8b5 100644
--- a/core/java/android/net/http/X509TrustManagerExtensions.java
+++ b/core/java/android/net/http/X509TrustManagerExtensions.java
@@ -16,6 +16,8 @@
 
 package android.net.http;
 
+import android.annotation.SystemApi;
+
 import com.android.org.conscrypt.TrustManagerImpl;
 
 import java.security.cert.CertificateException;
@@ -80,4 +82,15 @@
     public boolean isUserAddedCertificate(X509Certificate cert) {
         return mDelegate.isUserAddedCertificate(cert);
     }
+
+    /**
+     * Returns {@code true} if the TrustManager uses the same trust configuration for the provided
+     * hostnames.
+     *
+     * @hide
+     */
+    @SystemApi
+    public boolean isSameTrustConfiguration(String hostname1, String hostname2) {
+        return true;
+    }
 }
diff --git a/core/java/android/os/UserManagerInternal.java b/core/java/android/os/UserManagerInternal.java
index d7be6d8..b50cc79 100644
--- a/core/java/android/os/UserManagerInternal.java
+++ b/core/java/android/os/UserManagerInternal.java
@@ -36,7 +36,7 @@
      *
      * Must be called while taking the {@link #getUserRestrictionsLock()} lock.
      */
-    public abstract void updateEffectiveUserRestrictionsRL(int userId);
+    public abstract void updateEffectiveUserRestrictionsLR(int userId);
 
     /**
      * Called by {@link com.android.server.devicepolicy.DevicePolicyManagerService} to get
@@ -44,7 +44,7 @@
      *
      * Must be called while taking the {@link #getUserRestrictionsLock()} lock.
      */
-    public abstract void updateEffectiveUserRestrictionsForAllUsersRL();
+    public abstract void updateEffectiveUserRestrictionsForAllUsersLR();
 
     /**
      * Returns the "base" user restrictions.
diff --git a/core/java/android/webkit/WebViewFactory.java b/core/java/android/webkit/WebViewFactory.java
index 584deff..cb18b49 100644
--- a/core/java/android/webkit/WebViewFactory.java
+++ b/core/java/android/webkit/WebViewFactory.java
@@ -96,27 +96,49 @@
         public MissingWebViewPackageException(Exception e) { super(e); }
     }
 
-    public static String getWebViewPackageName() {
-        return AppGlobals.getInitialApplication().getString(
-                com.android.internal.R.string.config_webViewPackageName);
+    /** @hide */
+    public static String[] getWebViewPackageNames() {
+        return AppGlobals.getInitialApplication().getResources().getStringArray(
+                com.android.internal.R.array.config_webViewPackageNames);
     }
 
-    private static PackageInfo fetchPackageInfo() {
+    // TODO (gsennton) remove when committing webview xts test change
+    public static String getWebViewPackageName() {
+        String[] webViewPackageNames = getWebViewPackageNames();
+        return webViewPackageNames[webViewPackageNames.length-1];
+    }
+
+    /**
+     * Return the package info of the first package in the webview priority list that contains
+     * webview.
+     *
+     * @hide
+     */
+    public static PackageInfo findPreferredWebViewPackage() {
         PackageManager pm = AppGlobals.getInitialApplication().getPackageManager();
-        try {
-            return pm.getPackageInfo(getWebViewPackageName(), PackageManager.GET_META_DATA);
-        } catch (PackageManager.NameNotFoundException e) {
-            throw new MissingWebViewPackageException(e);
+
+        for (String packageName : getWebViewPackageNames()) {
+            try {
+                PackageInfo packageInfo = pm.getPackageInfo(packageName,
+                    PackageManager.GET_META_DATA);
+                ApplicationInfo applicationInfo = packageInfo.applicationInfo;
+
+                // If the correct flag is set the package contains webview.
+                if (getWebViewLibrary(applicationInfo) != null) {
+                    return packageInfo;
+                }
+            } catch (PackageManager.NameNotFoundException e) {
+            }
         }
+        throw new MissingWebViewPackageException("Could not find a loadable WebView package");
     }
 
     // throws MissingWebViewPackageException
     private static ApplicationInfo getWebViewApplicationInfo() {
-        if (sPackageInfo == null) {
-            return fetchPackageInfo().applicationInfo;
-        } else {
+        if (sPackageInfo == null)
+            return findPreferredWebViewPackage().applicationInfo;
+        else
             return sPackageInfo.applicationInfo;
-        }
     }
 
     private static String getWebViewLibrary(ApplicationInfo ai) {
@@ -134,7 +156,12 @@
      * name is the same as the one providing the webview.
      */
     public static int loadWebViewNativeLibraryFromPackage(String packageName) {
-        sPackageInfo = fetchPackageInfo();
+        try {
+            sPackageInfo = findPreferredWebViewPackage();
+        } catch (MissingWebViewPackageException e) {
+            return LIBLOAD_FAILED_LISTING_WEBVIEW_PACKAGES;
+        }
+
         if (packageName != null && packageName.equals(sPackageInfo.packageName)) {
             return loadNativeLibrary();
         }
@@ -180,7 +207,7 @@
     private static Class<WebViewFactoryProvider> getProviderClass() {
         try {
             // First fetch the package info so we can log the webview package version.
-            sPackageInfo = fetchPackageInfo();
+            sPackageInfo = findPreferredWebViewPackage();
             Log.i(LOGTAG, "Loading " + sPackageInfo.packageName + " version " +
                 sPackageInfo.versionName + " (code " + sPackageInfo.versionCode + ")");
 
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 400c822..76f7062 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2130,8 +2130,10 @@
         string that's stored in 8-bit unpacked format) characters.-->
     <bool translatable="false" name="config_sms_decode_gsm_8bit_data">false</bool>
 
-    <!-- Package name providing WebView implementation. -->
-    <string name="config_webViewPackageName" translatable="false">com.android.webview</string>
+    <!-- List of package names (ordered by preference) providing WebView implementations. -->
+    <string-array name="config_webViewPackageNames" translatable="false">
+      <item>com.android.webview</item>
+    </string-array>
 
     <!-- If EMS is not supported, framework breaks down EMS into single segment SMS
          and adds page info " x/y". This config is used to set which carrier doesn't
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index d1932fc..ebef6cc 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2019,7 +2019,7 @@
   <java-symbol type="attr" name="actionModeWebSearchDrawable" />
   <java-symbol type="string" name="websearch" />
   <java-symbol type="drawable" name="ic_media_video_poster" />
-  <java-symbol type="string" name="config_webViewPackageName" />
+  <java-symbol type="array" name="config_webViewPackageNames" />
 
   <!-- From SubtitleView -->
   <java-symbol type="dimen" name="subtitle_corner_radius" />
diff --git a/core/tests/coretests/AndroidManifest.xml b/core/tests/coretests/AndroidManifest.xml
index 3c10368..6903b7b 100644
--- a/core/tests/coretests/AndroidManifest.xml
+++ b/core/tests/coretests/AndroidManifest.xml
@@ -136,7 +136,9 @@
             </intent-filter>
         </activity>
 
-        <activity android:name="android.widget.TextViewActivity" android:label="TextViewActivity">
+        <activity android:name="android.widget.TextViewActivity"
+                android:label="TextViewActivity"
+                android:screenOrientation="portrait">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
diff --git a/core/tests/coretests/src/android/widget/TextViewActivityTest.java b/core/tests/coretests/src/android/widget/TextViewActivityTest.java
index 6a76a27..bb51570 100644
--- a/core/tests/coretests/src/android/widget/TextViewActivityTest.java
+++ b/core/tests/coretests/src/android/widget/TextViewActivityTest.java
@@ -36,7 +36,6 @@
 
 import android.test.ActivityInstrumentationTestCase2;
 import android.test.suitebuilder.annotation.SmallTest;
-import android.util.OrientationUtil;
 import android.view.KeyEvent;
 
 /**
@@ -44,16 +43,13 @@
  */
 public class TextViewActivityTest extends ActivityInstrumentationTestCase2<TextViewActivity>{
 
-    private OrientationUtil mOrientationUtil;
-
     public TextViewActivityTest() {
         super(TextViewActivity.class);
     }
 
     @Override
     public void setUp() {
-        mOrientationUtil = OrientationUtil.initializeAndStartActivityIfNotStarted(this);
-        mOrientationUtil.setPortraitOrientation();
+        getActivity();
     }
 
     @SmallTest
diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp
index 7c63e31..94a11f1 100644
--- a/libs/hwui/Caches.cpp
+++ b/libs/hwui/Caches.cpp
@@ -23,6 +23,7 @@
 #include "ShadowTessellator.h"
 #include "utils/GLUtils.h"
 
+#include <cutils/properties.h>
 #include <utils/Log.h>
 #include <utils/String8.h>
 
diff --git a/libs/hwui/Caches.h b/libs/hwui/Caches.h
index 61e958d..330dc29 100644
--- a/libs/hwui/Caches.h
+++ b/libs/hwui/Caches.h
@@ -43,7 +43,6 @@
 #include <GLES3/gl3.h>
 
 #include <utils/KeyedVector.h>
-#include <utils/Singleton.h>
 
 #include <cutils/compiler.h>
 
diff --git a/libs/hwui/Extensions.cpp b/libs/hwui/Extensions.cpp
index 06c8a21..6dd29ad 100644
--- a/libs/hwui/Extensions.cpp
+++ b/libs/hwui/Extensions.cpp
@@ -20,6 +20,7 @@
 #include "Properties.h"
 #include "utils/StringUtils.h"
 
+#include <GLES2/gl2.h>
 #include <GLES2/gl2ext.h>
 #include <utils/Log.h>
 
diff --git a/libs/hwui/Extensions.h b/libs/hwui/Extensions.h
index 0a30d16..6689b88 100644
--- a/libs/hwui/Extensions.h
+++ b/libs/hwui/Extensions.h
@@ -19,12 +19,6 @@
 
 #include <cutils/compiler.h>
 
-#include <utils/Singleton.h>
-#include <utils/SortedVector.h>
-#include <utils/String8.h>
-
-#include <GLES2/gl2.h>
-
 namespace android {
 namespace uirenderer {
 
diff --git a/libs/hwui/GradientCache.cpp b/libs/hwui/GradientCache.cpp
index aa105f9..8c46450 100644
--- a/libs/hwui/GradientCache.cpp
+++ b/libs/hwui/GradientCache.cpp
@@ -21,6 +21,8 @@
 #include "GradientCache.h"
 #include "Properties.h"
 
+#include <cutils/properties.h>
+
 namespace android {
 namespace uirenderer {
 
diff --git a/libs/hwui/PathCache.cpp b/libs/hwui/PathCache.cpp
index 4031f2e1..fd9ab18 100644
--- a/libs/hwui/PathCache.cpp
+++ b/libs/hwui/PathCache.cpp
@@ -30,6 +30,8 @@
 #include "thread/Signal.h"
 #include "thread/TaskProcessor.h"
 
+#include <cutils/properties.h>
+
 namespace android {
 namespace uirenderer {
 
diff --git a/libs/hwui/Properties.cpp b/libs/hwui/Properties.cpp
index c0c61db..e818186 100644
--- a/libs/hwui/Properties.cpp
+++ b/libs/hwui/Properties.cpp
@@ -17,8 +17,12 @@
 
 #include "Debug.h"
 
-#include <algorithm>
+#include <cutils/compiler.h>
 #include <cutils/log.h>
+#include <cutils/properties.h>
+
+#include <algorithm>
+#include <cstdlib>
 
 namespace android {
 namespace uirenderer {
diff --git a/libs/hwui/Properties.h b/libs/hwui/Properties.h
index 74cd74b..1293c78 100644
--- a/libs/hwui/Properties.h
+++ b/libs/hwui/Properties.h
@@ -18,8 +18,6 @@
 #define ANDROID_HWUI_PROPERTIES_H
 
 #include <cutils/properties.h>
-#include <stdlib.h>
-#include <utils/Singleton.h>
 
 /**
  * This file contains the list of system properties used to configure
diff --git a/libs/hwui/RenderBufferCache.cpp b/libs/hwui/RenderBufferCache.cpp
index 8beed25..11d7a6a 100644
--- a/libs/hwui/RenderBufferCache.cpp
+++ b/libs/hwui/RenderBufferCache.cpp
@@ -14,12 +14,14 @@
  * limitations under the License.
  */
 
-#include <utils/Log.h>
-
 #include "Debug.h"
 #include "Properties.h"
 #include "RenderBufferCache.h"
 
+#include <utils/Log.h>
+
+#include <cstdlib>
+
 namespace android {
 namespace uirenderer {
 
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index 15ccd6a..a1107f0 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -563,10 +563,7 @@
 void* RenderProxy::postAndWait(MethodInvokeRenderTask* task) {
     void* retval;
     task->setReturnPtr(&retval);
-    SignalingRenderTask syncTask(task, &mSyncMutex, &mSyncCondition);
-    AutoMutex _lock(mSyncMutex);
-    mRenderThread.queue(&syncTask);
-    mSyncCondition.wait(mSyncMutex);
+    mRenderThread.queueAndWait(task);
     return retval;
 }
 
diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h
index 338fab6..d0e601e 100644
--- a/libs/hwui/renderthread/RenderProxy.h
+++ b/libs/hwui/renderthread/RenderProxy.h
@@ -117,9 +117,6 @@
 
     DrawFrameTask mDrawFrameTask;
 
-    Mutex mSyncMutex;
-    Condition mSyncCondition;
-
     void destroyContext();
 
     void post(RenderTask* task);
diff --git a/libs/hwui/renderthread/RenderThread.cpp b/libs/hwui/renderthread/RenderThread.cpp
index 8fcd109..526a848 100644
--- a/libs/hwui/renderthread/RenderThread.cpp
+++ b/libs/hwui/renderthread/RenderThread.cpp
@@ -28,9 +28,6 @@
 #include <utils/Log.h>
 
 namespace android {
-using namespace uirenderer::renderthread;
-ANDROID_SINGLETON_STATIC_INSTANCE(RenderThread);
-
 namespace uirenderer {
 namespace renderthread {
 
@@ -136,7 +133,22 @@
     }
 };
 
-RenderThread::RenderThread() : Thread(true), Singleton<RenderThread>()
+static bool gHasRenderThreadInstance = false;
+
+bool RenderThread::hasInstance() {
+    return gHasRenderThreadInstance;
+}
+
+RenderThread& RenderThread::getInstance() {
+    // This is a pointer because otherwise __cxa_finalize
+    // will try to delete it like a Good Citizen but that causes us to crash
+    // because we don't want to delete the RenderThread normally.
+    static RenderThread* sInstance = new RenderThread();
+    gHasRenderThreadInstance = true;
+    return *sInstance;
+}
+
+RenderThread::RenderThread() : Thread(true)
         , mNextWakeup(LLONG_MAX)
         , mDisplayEventReceiver(nullptr)
         , mVsyncRequested(false)
@@ -313,13 +325,10 @@
 }
 
 void RenderThread::queueAndWait(RenderTask* task) {
-    Mutex mutex;
-    Condition condition;
-    SignalingRenderTask syncTask(task, &mutex, &condition);
-
-    AutoMutex _lock(mutex);
+    SignalingRenderTask syncTask(task, &mSyncMutex, &mSyncCondition);
+    AutoMutex _lock(mSyncMutex);
     queue(&syncTask);
-    condition.wait(mutex);
+    mSyncCondition.wait(mSyncMutex);
 }
 
 void RenderThread::queueAtFront(RenderTask* task) {
diff --git a/libs/hwui/renderthread/RenderThread.h b/libs/hwui/renderthread/RenderThread.h
index f3444a8..d8c7e61 100644
--- a/libs/hwui/renderthread/RenderThread.h
+++ b/libs/hwui/renderthread/RenderThread.h
@@ -25,11 +25,11 @@
 #include <cutils/compiler.h>
 #include <ui/DisplayInfo.h>
 #include <utils/Looper.h>
-#include <utils/Mutex.h>
-#include <utils/Singleton.h>
 #include <utils/Thread.h>
 
+#include <condition_variable>
 #include <memory>
+#include <mutex>
 #include <set>
 
 namespace android {
@@ -72,7 +72,7 @@
     ~IFrameCallback() {}
 };
 
-class ANDROID_API RenderThread : public Thread, protected Singleton<RenderThread> {
+class ANDROID_API RenderThread : public Thread {
 public:
     // RenderThread takes complete ownership of tasks that are queued
     // and will delete them after they are run
@@ -100,7 +100,6 @@
     virtual bool threadLoop() override;
 
 private:
-    friend class Singleton<RenderThread>;
     friend class DispatchFrameCallbacks;
     friend class RenderProxy;
     friend class android::uirenderer::TestUtils;
@@ -108,6 +107,9 @@
     RenderThread();
     virtual ~RenderThread();
 
+    static bool hasInstance();
+    static RenderThread& getInstance();
+
     void initThreadLocals();
     void initializeDisplayEventReceiver();
     static int displayEventReceiverCallback(int fd, int events, void* data);
@@ -125,6 +127,8 @@
 
     nsecs_t mNextWakeup;
     TaskQueue mQueue;
+    Mutex mSyncMutex;
+    Condition mSyncCondition;
 
     DisplayInfo mDisplayInfo;
 
diff --git a/libs/hwui/unit_tests/FatVectorTests.cpp b/libs/hwui/unit_tests/FatVectorTests.cpp
index 1f1f50a..3ef329a 100644
--- a/libs/hwui/unit_tests/FatVectorTests.cpp
+++ b/libs/hwui/unit_tests/FatVectorTests.cpp
@@ -99,9 +99,9 @@
         FatVector<TestUtils::SignalingDtor, 0> v;
         v.emplace_back(&count);
         EXPECT_FALSE(allocationIsInternal(v));
-        EXPECT_EQ(0, count);
+        EXPECT_EQ(0, count) << "Destruction shouldn't have happened yet";
     }
-    EXPECT_EQ(1, count);
+    EXPECT_EQ(1, count) << "Destruction should happen exactly once";
 }
 
 TEST(FatVector, destructorExternal) {
@@ -113,7 +113,7 @@
             v.emplace_back(&count);
             EXPECT_TRUE(allocationIsInternal(v));
         }
-        EXPECT_EQ(0, count);
+        EXPECT_EQ(0, count) << "Destruction shouldn't have happened yet";
     }
-    EXPECT_EQ(10, count);
+    EXPECT_EQ(10, count) << "Destruction should happen exactly once";
 }
diff --git a/libs/hwui/unit_tests/OpReordererTests.cpp b/libs/hwui/unit_tests/OpReordererTests.cpp
index cef46f7..09b10c3 100644
--- a/libs/hwui/unit_tests/OpReordererTests.cpp
+++ b/libs/hwui/unit_tests/OpReordererTests.cpp
@@ -44,15 +44,24 @@
 class TestRendererBase {
 public:
     virtual ~TestRendererBase() {}
-    virtual OffscreenBuffer* createLayer(uint32_t, uint32_t) { ADD_FAILURE(); return nullptr; }
-    virtual void startLayer(OffscreenBuffer*) { ADD_FAILURE(); }
-    virtual void endLayer() { ADD_FAILURE(); }
+    virtual OffscreenBuffer* createLayer(uint32_t, uint32_t) {
+        ADD_FAILURE() << "Layer creation not expected in this test";
+        return nullptr;
+    }
+    virtual void startLayer(OffscreenBuffer*) {
+        ADD_FAILURE() << "Layer repaint not expected in this test";
+    }
+    virtual void endLayer() {
+        ADD_FAILURE() << "Layer updates not expected in this test";
+    }
     virtual void startFrame(uint32_t width, uint32_t height) {}
     virtual void endFrame() {}
 
     // define virtual defaults for direct
 #define BASE_OP_METHOD(Type) \
-    virtual void on##Type(const Type&, const BakedOpState&) { ADD_FAILURE(); }
+    virtual void on##Type(const Type&, const BakedOpState&) { \
+        ADD_FAILURE() << #Type " not expected in this test"; \
+    }
     MAP_OPS(BASE_OP_METHOD)
     int getIndex() { return mIndex; }
 
@@ -370,11 +379,11 @@
     void onRectOp(const RectOp& op, const BakedOpState& state) override {
         EXPECT_EQ(1, mIndex++);
 
-        // verify transform is reset
-        EXPECT_TRUE(state.computedState.transform.isIdentity());
+        EXPECT_TRUE(state.computedState.transform.isIdentity())
+                << "Transform should be reset within layer";
 
-        // verify damage rect is used as clip
-        EXPECT_EQ(state.computedState.clipRect, Rect(25, 25, 75, 75));
+        EXPECT_EQ(state.computedState.clipRect, Rect(25, 25, 75, 75))
+                << "Damage rect should be used to clip layer content";
     }
     void endLayer() override {
         EXPECT_EQ(2, mIndex++);
diff --git a/libs/hwui/unit_tests/RecordingCanvasTests.cpp b/libs/hwui/unit_tests/RecordingCanvasTests.cpp
index e8cdf46..dcf1f64 100644
--- a/libs/hwui/unit_tests/RecordingCanvasTests.cpp
+++ b/libs/hwui/unit_tests/RecordingCanvasTests.cpp
@@ -53,7 +53,7 @@
         ASSERT_EQ(Rect(0, 0, 100, 200), op.localClipRect);
         ASSERT_EQ(Rect(10, 20, 90, 180), op.unmappedBounds);
     });
-    ASSERT_EQ(1, count); // only one observed
+    ASSERT_EQ(1, count);
 }
 
 TEST(RecordingCanvas, backgroundAndImage) {
@@ -106,7 +106,7 @@
         }
         count++;
     });
-    ASSERT_EQ(2, count); // two draws observed
+    ASSERT_EQ(2, count);
 }
 
 TEST(RecordingCanvas, saveLayerSimple) {
@@ -121,7 +121,9 @@
         switch(count++) {
         case 0:
             EXPECT_EQ(RecordedOpId::BeginLayerOp, op.opId);
-            // TODO: add asserts
+            EXPECT_EQ(Rect(10, 20, 190, 180), op.unmappedBounds);
+            EXPECT_EQ(Rect(0, 0, 200, 200), op.localClipRect);
+            EXPECT_TRUE(op.localMatrix.isIdentity());
             break;
         case 1:
             EXPECT_EQ(RecordedOpId::RectOp, op.opId);
@@ -132,7 +134,7 @@
             break;
         case 2:
             EXPECT_EQ(RecordedOpId::EndLayerOp, op.opId);
-            // TODO: add asserts
+            // Don't bother asserting recording state data - it's not used
             break;
         default:
             ADD_FAILURE();
@@ -155,10 +157,8 @@
         if (count++ == 1) {
             Matrix4 expectedMatrix;
             EXPECT_EQ(RecordedOpId::RectOp, op.opId);
-
-            // recorded clip rect should be intersection of
-            // viewport and saveLayer bounds, in layer space
-            EXPECT_EQ(Rect(0, 0, 100, 100), op.localClipRect);
+            EXPECT_EQ(Rect(0, 0, 100, 100), op.localClipRect) << "Recorded clip rect should be"
+                    " intersection of viewport and saveLayer bounds, in layer space";
             EXPECT_EQ(Rect(0, 0, 400, 400), op.unmappedBounds);
             expectedMatrix.loadTranslate(-100, -100, 0);
             EXPECT_MATRIX_APPROX_EQ(expectedMatrix, op.localMatrix);
@@ -183,14 +183,11 @@
     int count = 0;
     playbackOps(*dl, [&count](const RecordedOp& op) {
         if (count++ == 1) {
-            Matrix4 expectedMatrix;
             EXPECT_EQ(RecordedOpId::RectOp, op.opId);
-
-            // recorded rect doesn't see rotate, since recorded relative to saveLayer bounds
             EXPECT_EQ(Rect(0, 0, 100, 100), op.localClipRect);
             EXPECT_EQ(Rect(0, 0, 100, 100), op.unmappedBounds);
-            expectedMatrix.loadIdentity();
-            EXPECT_MATRIX_APPROX_EQ(expectedMatrix, op.localMatrix);
+            EXPECT_MATRIX_APPROX_EQ(Matrix4::identity(), op.localMatrix)
+                    << "Recorded op shouldn't see any canvas transform before the saveLayer";
         }
     });
     EXPECT_EQ(3, count);
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
index a09a22a..59e09a1 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
@@ -66,7 +66,6 @@
 import android.support.v7.widget.RecyclerView.OnItemTouchListener;
 import android.support.v7.widget.RecyclerView.RecyclerListener;
 import android.support.v7.widget.RecyclerView.ViewHolder;
-import android.support.v7.widget.SimpleItemAnimator;
 import android.text.TextUtils;
 import android.text.format.DateUtils;
 import android.text.format.Formatter;
@@ -162,6 +161,9 @@
     private MessageBar mMessageBar;
     private View mProgressBar;
 
+    private int mSelectedItemColor;
+    private int mDefaultItemColor;
+
     public static void showNormal(FragmentManager fm, RootInfo root, DocumentInfo doc, int anim) {
         show(fm, TYPE_NORMAL, root, doc, null, anim);
     }
@@ -254,8 +256,7 @@
                     }
                 });
 
-        // TODO: Restore transition animations.  See b/24802917.
-        ((SimpleItemAnimator) mRecView.getItemAnimator()).setSupportsChangeAnimations(false);
+        mRecView.setItemAnimator(new DirectoryItemAnimator(getActivity()));
 
         // TODO: Add a divider between views (which might use RecyclerView.ItemDecoration).
         if (DEBUG_ENABLE_DND) {
@@ -293,6 +294,13 @@
         mAdapter = new DocumentsAdapter(context);
         mRecView.setAdapter(mAdapter);
 
+        mDefaultItemColor = context.getResources().getColor(android.R.color.transparent);
+        // Get the accent color.
+        TypedValue selColor = new TypedValue();
+        context.getTheme().resolveAttribute(android.R.attr.colorAccent, selColor, true);
+        // Set the opacity to 10%.
+        mSelectedItemColor = (selColor.data & 0x00ffffff) | 0x16000000;
+
         GestureDetector.SimpleOnGestureListener listener =
                 new GestureDetector.SimpleOnGestureListener() {
                     @Override
@@ -897,24 +905,26 @@
     // Provide a reference to the views for each data item
     // Complex data items may need more than one view per item, and
     // you provide access to all the views for a data item in a view holder
-    private static final class DocumentHolder
+    private final class DocumentHolder
             extends RecyclerView.ViewHolder
             implements View.OnKeyListener
     {
-        // each data item is just a string in this case
-        public View view;
         public String docId;  // The stable document id.
         private ClickListener mClickListener;
         private View.OnKeyListener mKeyListener;
 
         public DocumentHolder(View view) {
             super(view);
-            this.view = view;
             // Setting this using android:focusable in the item layouts doesn't work for list items.
             // So we set it here.  Note that touch mode focus is a separate issue - see
             // View.setFocusableInTouchMode and View.isInTouchMode for more info.
-            this.view.setFocusable(true);
-            this.view.setOnKeyListener(this);
+            view.setFocusable(true);
+            view.setOnKeyListener(this);
+        }
+
+        public void setSelected(boolean selected) {
+            itemView.setActivated(selected);
+            itemView.setBackgroundColor(selected ? mSelectedItemColor : mDefaultItemColor);
         }
 
         @Override
@@ -943,10 +953,10 @@
             checkState(mKeyListener == null);
             mKeyListener = listener;
         }
+    }
 
-        interface ClickListener {
-            public void onClick(DocumentHolder doc);
-        }
+    interface ClickListener {
+        public void onClick(DocumentHolder doc);
     }
 
     void showEmptyView() {
@@ -1005,6 +1015,24 @@
             return holder;
         }
 
+        /**
+         * Deal with selection changed events by using a custom ItemAnimator that just changes the
+         * background color.  This works around focus issues (otherwise items lose focus when their
+         * selection state changes) but also optimizes change animations for selection.
+         */
+        @Override
+        public void onBindViewHolder(DocumentHolder holder, int position, List<Object> payload) {
+            final View itemView = holder.itemView;
+
+            if (payload.contains(MultiSelectManager.SELECTION_CHANGED_MARKER)) {
+                final boolean selected = isSelected(position);
+                itemView.setActivated(selected);
+                return;
+            } else {
+                onBindViewHolder(holder, position);
+            }
+        }
+
         @Override
         public void onBindViewHolder(DocumentHolder holder, int position) {
 
@@ -1030,8 +1058,9 @@
             final long docSize = getCursorLong(cursor, Document.COLUMN_SIZE);
 
             holder.docId = docId;
-            final View itemView = holder.view;
-            itemView.setActivated(isSelected(position));
+            final View itemView = holder.itemView;
+
+            holder.setSelected(isSelected(position));
 
             final View line1 = itemView.findViewById(R.id.line1);
             final View line2 = itemView.findViewById(R.id.line2);
@@ -1959,7 +1988,7 @@
         }
     }
 
-    private class ItemClickListener implements DocumentHolder.ClickListener {
+    private class ItemClickListener implements ClickListener {
         @Override
         public void onClick(DocumentHolder doc) {
             final int position = doc.getAdapterPosition();
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DirectoryItemAnimator.java b/packages/DocumentsUI/src/com/android/documentsui/DirectoryItemAnimator.java
new file mode 100644
index 0000000..0eb1ea5
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/DirectoryItemAnimator.java
@@ -0,0 +1,195 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+
+package com.android.documentsui;
+
+import android.animation.Animator;
+import android.animation.ArgbEvaluator;
+import android.animation.ValueAnimator;
+import android.content.Context;
+import android.support.v4.util.ArrayMap;
+import android.support.v7.widget.DefaultItemAnimator;
+import android.support.v7.widget.RecyclerView;
+import android.util.TypedValue;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Performs change animations on Items in DirectoryFragment's RecyclerView.  This class overrides
+ * the way selection animations are normally performed - instead of cross fading the old Item with a
+ * new Item, this class manually animates a background color change.  This enables selected Items to
+ * correctly maintain focus.
+ */
+class DirectoryItemAnimator extends DefaultItemAnimator {
+    private final List<ColorAnimation> mPendingAnimations = new ArrayList<>();
+    private final Map<RecyclerView.ViewHolder, ColorAnimation> mRunningAnimations =
+            new ArrayMap<>();
+    private final Integer mDefaultColor;
+    private final Integer mSelectedColor;
+
+    public DirectoryItemAnimator(Context context) {
+        mDefaultColor = context.getResources().getColor(android.R.color.transparent);
+        // Get the accent color.
+        TypedValue selColor = new TypedValue();
+        context.getTheme().resolveAttribute(android.R.attr.colorAccent, selColor, true);
+        // Set the opacity to 10%.
+        mSelectedColor = (selColor.data & 0x00ffffff) | 0x16000000;
+    }
+
+    @Override
+    public void runPendingAnimations() {
+        super.runPendingAnimations();
+        for (ColorAnimation anim: mPendingAnimations) {
+            anim.start();
+            mRunningAnimations.put(anim.viewHolder, anim);
+        }
+        mPendingAnimations.clear();
+    }
+
+    @Override
+    public void endAnimation(RecyclerView.ViewHolder vh) {
+        super.endAnimation(vh);
+
+        for (int i = mPendingAnimations.size() - 1; i >= 0; --i) {
+            ColorAnimation anim = mPendingAnimations.get(i);
+            if (anim.viewHolder == vh) {
+                mPendingAnimations.remove(i);
+                anim.end();
+            }
+        }
+
+        ColorAnimation anim = mRunningAnimations.get(vh);
+        if (anim != null) {
+            anim.cancel();
+        }
+    }
+
+    @Override
+    public ItemHolderInfo recordPreLayoutInformation(
+        RecyclerView.State state,
+        RecyclerView.ViewHolder viewHolder,
+        @AdapterChanges int changeFlags,
+        List<Object> payloads) {
+        ItemInfo info = (ItemInfo) super.recordPreLayoutInformation(state,
+                viewHolder, changeFlags, payloads);
+        info.isActivated = viewHolder.itemView.isActivated();
+        return info;
+    }
+
+
+    @Override
+    public ItemHolderInfo recordPostLayoutInformation(
+        RecyclerView.State state, RecyclerView.ViewHolder viewHolder) {
+        ItemInfo info = (ItemInfo) super.recordPostLayoutInformation(state,
+                viewHolder);
+        info.isActivated = viewHolder.itemView.isActivated();
+        return info;
+    }
+
+    @Override
+    public boolean animateChange(final RecyclerView.ViewHolder oldHolder,
+            RecyclerView.ViewHolder newHolder, ItemHolderInfo preInfo,
+            ItemHolderInfo postInfo) {
+        if (oldHolder != newHolder) {
+            return super.animateChange(oldHolder, newHolder, preInfo, postInfo);
+        }
+
+        ItemInfo pre = (ItemInfo)preInfo;
+        ItemInfo post = (ItemInfo)postInfo;
+
+        if (pre.isActivated == post.isActivated) {
+            dispatchAnimationFinished(oldHolder);
+            return false;
+        } else {
+            Integer startColor = pre.isActivated ? mSelectedColor : mDefaultColor;
+            Integer endColor = post.isActivated ? mSelectedColor : mDefaultColor;
+            oldHolder.itemView.setBackgroundColor(startColor);
+            mPendingAnimations.add(new ColorAnimation(oldHolder, startColor, endColor));
+        }
+        return true;
+    }
+
+    @Override
+    public ItemHolderInfo obtainHolderInfo() {
+        return new ItemInfo();
+    }
+
+    @Override
+    public boolean canReuseUpdatedViewHolder(RecyclerView.ViewHolder vh) {
+        return true;
+    }
+
+    class ItemInfo extends DefaultItemAnimator.ItemHolderInfo {
+        boolean isActivated;
+    };
+
+    /**
+     * Animates changes in background color.
+     */
+    class ColorAnimation
+            implements ValueAnimator.AnimatorUpdateListener, Animator.AnimatorListener {
+        ValueAnimator mValueAnimator;
+        final RecyclerView.ViewHolder viewHolder;
+        int mEndColor;
+
+        public ColorAnimation(RecyclerView.ViewHolder vh, int startColor, int endColor)
+        {
+            viewHolder = vh;
+            mValueAnimator = ValueAnimator.ofObject(new ArgbEvaluator(), startColor, endColor);
+            mValueAnimator.addUpdateListener(this);
+            mValueAnimator.addListener(this);
+
+            mEndColor = endColor;
+        }
+
+        public void start() {
+            mValueAnimator.start();
+        }
+
+        public void cancel() {
+            mValueAnimator.cancel();
+        }
+
+        public void end() {
+            mValueAnimator.end();
+        }
+
+        @Override
+        public void onAnimationUpdate(ValueAnimator animator) {
+            viewHolder.itemView.setBackgroundColor((Integer)animator.getAnimatedValue());
+        }
+
+        @Override
+        public void onAnimationEnd(Animator animator) {
+            viewHolder.itemView.setBackgroundColor(mEndColor);
+            mRunningAnimations.remove(viewHolder);
+            dispatchAnimationFinished(viewHolder);
+        }
+
+        @Override
+        public void onAnimationStart(Animator animation) {
+            dispatchAnimationStarted(viewHolder);
+        }
+
+        @Override
+        public void onAnimationCancel(Animator animation) {}
+
+        @Override
+        public void onAnimationRepeat(Animator animation) {}
+    };
+};
diff --git a/packages/DocumentsUI/src/com/android/documentsui/MultiSelectManager.java b/packages/DocumentsUI/src/com/android/documentsui/MultiSelectManager.java
index ef53d53..4fde6ff 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/MultiSelectManager.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/MultiSelectManager.java
@@ -76,6 +76,9 @@
     private Adapter<?> mAdapter;
     private boolean mSingleSelect;
 
+    // Payloads for notifyItemChange to distinguish between selection and other events.
+    public static final String SELECTION_CHANGED_MARKER = "Selection-Changed";
+
     @Nullable private BandController mBandManager;
 
     /**
@@ -460,7 +463,7 @@
         for (int i = lastListener; i > -1; i--) {
             mCallbacks.get(i).onItemStateChanged(position, selected);
         }
-        mAdapter.notifyItemChanged(position);
+        mAdapter.notifyItemChanged(position, SELECTION_CHANGED_MARKER);
     }
 
     /**
diff --git a/packages/Shell/src/com/android/shell/BugreportReceiver.java b/packages/Shell/src/com/android/shell/BugreportReceiver.java
index 0d1ad19..e90a3b5 100644
--- a/packages/Shell/src/com/android/shell/BugreportReceiver.java
+++ b/packages/Shell/src/com/android/shell/BugreportReceiver.java
@@ -136,9 +136,10 @@
         // EXTRA_TEXT should be an ArrayList, but some clients are expecting a single String.
         // So, to avoid an exception on Intent.migrateExtraStreamToClipData(), we need to manually
         // create the ClipData object with the attachments URIs.
-        intent.putExtra(Intent.EXTRA_TEXT, SystemProperties.get("ro.build.description"));
-        final ClipData clipData = new ClipData(
-                null, new String[] { mimeType },
+        String messageBody = String.format("Build info: %s\nSerial number:%s",
+                SystemProperties.get("ro.build.description"), SystemProperties.get("ro.serialno"));
+        intent.putExtra(Intent.EXTRA_TEXT, messageBody);
+        final ClipData clipData = new ClipData(null, new String[] { mimeType },
                 new ClipData.Item(null, null, null, bugreportUri));
         clipData.addItem(new ClipData.Item(null, null, null, screenshotUri));
         intent.setClipData(clipData);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Recents.java b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
index 4d40cb7..a58bc58 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Recents.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
@@ -21,9 +21,11 @@
 import android.content.Intent;
 import android.content.ServiceConnection;
 import android.content.res.Configuration;
+import android.os.Build;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.RemoteException;
+import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.util.Log;
 import android.view.Display;
@@ -52,10 +54,21 @@
     public final static int EVENT_BUS_PRIORITY = 1;
     public final static int BIND_TO_SYSTEM_USER_RETRY_DELAY = 5000;
 
+    // Purely for experimentation
+    private final static String RECENTS_OVERRIDE_SYSPROP_KEY = "persist.recents_override_pkg";
+    private final static String ACTION_SHOW_RECENTS = "com.android.systemui.recents.ACTION_SHOW";
+    private final static String ACTION_HIDE_RECENTS = "com.android.systemui.recents.ACTION_HIDE";
+    private final static String ACTION_TOGGLE_RECENTS = "com.android.systemui.recents.ACTION_TOGGLE";
+
     private static SystemServicesProxy sSystemServicesProxy;
     private static RecentsTaskLoader sTaskLoader;
     private static RecentsConfiguration sConfiguration;
 
+    // For experiments only, allows another package to handle recents if it is defined in the system
+    // properties.  This is limited to show/toggle/hide, and does not tie into the ActivityManager,
+    // and does not reside in the home stack.
+    private String mOverrideRecentsPackageName;
+
     private Handler mHandler;
     private RecentsImpl mImpl;
 
@@ -142,6 +155,14 @@
         mHandler = new Handler();
         mImpl = new RecentsImpl(mContext);
 
+        // Check if there is a recents override package
+        if ("userdebug".equals(Build.TYPE) || "eng".equals(Build.TYPE)) {
+            String cnStr = SystemProperties.get(RECENTS_OVERRIDE_SYSPROP_KEY);
+            if (!cnStr.isEmpty()) {
+                mOverrideRecentsPackageName = cnStr;
+            }
+        }
+
         // Register with the event bus
         EventBus.getDefault().register(this, EVENT_BUS_PRIORITY);
         EventBus.getDefault().register(sTaskLoader, EVENT_BUS_PRIORITY);
@@ -172,6 +193,10 @@
      */
     @Override
     public void showRecents(boolean triggeredFromAltTab, View statusBarView) {
+        if (proxyToOverridePackage(ACTION_SHOW_RECENTS)) {
+            return;
+        }
+
         int currentUser = sSystemServicesProxy.getCurrentUser();
         if (sSystemServicesProxy.isSystemUser(currentUser)) {
             mImpl.showRecents(triggeredFromAltTab);
@@ -197,6 +222,10 @@
      */
     @Override
     public void hideRecents(boolean triggeredFromAltTab, boolean triggeredFromHomeKey) {
+        if (proxyToOverridePackage(ACTION_HIDE_RECENTS)) {
+            return;
+        }
+
         int currentUser = sSystemServicesProxy.getCurrentUser();
         if (sSystemServicesProxy.isSystemUser(currentUser)) {
             mImpl.hideRecents(triggeredFromAltTab, triggeredFromHomeKey);
@@ -222,6 +251,10 @@
      */
     @Override
     public void toggleRecents(Display display, int layoutDirection, View statusBarView) {
+        if (proxyToOverridePackage(ACTION_TOGGLE_RECENTS)) {
+            return;
+        }
+
         int currentUser = sSystemServicesProxy.getCurrentUser();
         if (sSystemServicesProxy.isSystemUser(currentUser)) {
             mImpl.toggleRecents();
@@ -421,4 +454,19 @@
         }
         mOnConnectRunnables.clear();
     }
+
+    /**
+     * Attempts to proxy the following action to the override recents package.
+     * @return whether the proxying was successful
+     */
+    private boolean proxyToOverridePackage(String action) {
+        if (mOverrideRecentsPackageName != null) {
+            Intent intent = new Intent(action);
+            intent.setPackage(mOverrideRecentsPackageName);
+            intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
+            mContext.sendBroadcast(intent);
+            return true;
+        }
+        return false;
+    }
 }
diff --git a/services/core/java/com/android/server/MountService.java b/services/core/java/com/android/server/MountService.java
index 85187c7..87ae3dc 100644
--- a/services/core/java/com/android/server/MountService.java
+++ b/services/core/java/com/android/server/MountService.java
@@ -562,6 +562,8 @@
     private static final int H_VOLUME_BROADCAST = 6;
     private static final int H_INTERNAL_BROADCAST = 7;
     private static final int H_VOLUME_UNMOUNT = 8;
+    private static final int H_PARTITION_FORGET = 9;
+    private static final int H_RESET = 10;
 
     class MountServiceHandler extends Handler {
         public MountServiceHandler(Looper looper) {
@@ -669,6 +671,16 @@
                     final Intent intent = (Intent) msg.obj;
                     mContext.sendBroadcastAsUser(intent, UserHandle.ALL,
                             android.Manifest.permission.WRITE_MEDIA_STORAGE);
+                    break;
+                }
+                case H_PARTITION_FORGET: {
+                    final String partGuid = (String) msg.obj;
+                    forgetPartition(partGuid);
+                    break;
+                }
+                case H_RESET: {
+                    resetIfReadyAndConnected();
+                    break;
                 }
             }
         }
@@ -753,9 +765,7 @@
     }
 
     private void handleSystemReady() {
-        synchronized (mLock) {
-            resetIfReadyAndConnectedLocked();
-        }
+        resetIfReadyAndConnected();
 
         // Start scheduling nominally-daily fstrim operations
         MountServiceIdler.scheduleIdlePass(mContext);
@@ -793,7 +803,7 @@
         }
     }
 
-    private void addInternalVolume() {
+    private void addInternalVolumeLocked() {
         // Create a stub volume that represents internal storage
         final VolumeInfo internal = new VolumeInfo(VolumeInfo.ID_PRIVATE_INTERNAL,
                 VolumeInfo.TYPE_PRIVATE, null, null);
@@ -802,18 +812,22 @@
         mVolumes.put(internal.id, internal);
     }
 
-    private void resetIfReadyAndConnectedLocked() {
+    private void resetIfReadyAndConnected() {
         Slog.d(TAG, "Thinking about reset, mSystemReady=" + mSystemReady
                 + ", mDaemonConnected=" + mDaemonConnected);
         if (mSystemReady && mDaemonConnected) {
-            final UserManager um = UserManager.get(mContext);
-            final List<UserInfo> users = um.getUsers();
+            final List<UserInfo> users = mContext.getSystemService(UserManager.class).getUsers();
             killMediaProvider(users);
 
-            mDisks.clear();
-            mVolumes.clear();
+            final int[] startedUsers;
+            synchronized (mLock) {
+                startedUsers = mStartedUsers;
 
-            addInternalVolume();
+                mDisks.clear();
+                mVolumes.clear();
+
+                addInternalVolumeLocked();
+            }
 
             try {
                 mConnector.execute("volume", "reset");
@@ -822,7 +836,7 @@
                 for (UserInfo user : users) {
                     mConnector.execute("volume", "user_added", user.id, user.serialNumber);
                 }
-                for (int userId : mStartedUsers) {
+                for (int userId : startedUsers) {
                     mConnector.execute("volume", "user_started", userId);
                 }
             } catch (NativeDaemonConnectorException e) {
@@ -898,9 +912,7 @@
     }
 
     private void handleDaemonConnected() {
-        synchronized (mLock) {
-            resetIfReadyAndConnectedLocked();
-        }
+        resetIfReadyAndConnected();
 
         /*
          * Now that we've done our initialization, release
@@ -1428,6 +1440,7 @@
         mConnector = new NativeDaemonConnector(this, "vold", MAX_CONTAINERS * 2, VOLD_TAG, 25,
                 null);
         mConnector.setDebug(true);
+        mConnector.setLockWarning(mLock);
 
         Thread thread = new Thread(mConnector, VOLD_TAG);
         thread.start();
@@ -1445,7 +1458,9 @@
         userFilter.addAction(Intent.ACTION_USER_REMOVED);
         mContext.registerReceiver(mUserReceiver, userFilter, null, mHandler);
 
-        addInternalVolume();
+        synchronized (mLock) {
+            addInternalVolumeLocked();
+        }
 
         // Add ourself to the Watchdog monitors if enabled.
         if (WATCHDOG_ENABLE) {
@@ -1791,10 +1806,11 @@
         waitForReady();
 
         Preconditions.checkNotNull(fsUuid);
+
         synchronized (mLock) {
             final VolumeRecord rec = mRecords.remove(fsUuid);
             if (rec != null && !TextUtils.isEmpty(rec.partGuid)) {
-                forgetPartition(rec.partGuid);
+                mHandler.obtainMessage(H_PARTITION_FORGET, rec.partGuid).sendToTarget();
             }
             mCallbacks.notifyVolumeForgotten(fsUuid);
 
@@ -1802,7 +1818,7 @@
             // reset vold so we bind into new volume into place.
             if (Objects.equals(mPrimaryStorageUuid, fsUuid)) {
                 mPrimaryStorageUuid = getDefaultPrimaryStorageUuid();
-                resetIfReadyAndConnectedLocked();
+                mHandler.obtainMessage(H_RESET).sendToTarget();
             }
 
             writeSettingsLocked();
@@ -1819,7 +1835,7 @@
                 final String fsUuid = mRecords.keyAt(i);
                 final VolumeRecord rec = mRecords.valueAt(i);
                 if (!TextUtils.isEmpty(rec.partGuid)) {
-                    forgetPartition(rec.partGuid);
+                    mHandler.obtainMessage(H_PARTITION_FORGET, rec.partGuid).sendToTarget();
                 }
                 mCallbacks.notifyVolumeForgotten(fsUuid);
             }
@@ -1830,7 +1846,7 @@
             }
 
             writeSettingsLocked();
-            resetIfReadyAndConnectedLocked();
+            mHandler.obtainMessage(H_RESET).sendToTarget();
         }
     }
 
@@ -1878,7 +1894,7 @@
             }
 
             writeSettingsLocked();
-            resetIfReadyAndConnectedLocked();
+            mHandler.obtainMessage(H_RESET).sendToTarget();
         }
     }
 
@@ -1915,7 +1931,7 @@
                 Slog.d(TAG, "Skipping move to/from primary physical");
                 onMoveStatusLocked(MOVE_STATUS_COPY_FINISHED);
                 onMoveStatusLocked(PackageManager.MOVE_SUCCEEDED);
-                resetIfReadyAndConnectedLocked();
+                mHandler.obtainMessage(H_RESET).sendToTarget();
 
             } else {
                 final VolumeInfo from = findStorageForUuid(mPrimaryStorageUuid);
diff --git a/services/core/java/com/android/server/NativeDaemonConnector.java b/services/core/java/com/android/server/NativeDaemonConnector.java
index 519a2a3..3a6fa05 100644
--- a/services/core/java/com/android/server/NativeDaemonConnector.java
+++ b/services/core/java/com/android/server/NativeDaemonConnector.java
@@ -25,6 +25,7 @@
 import android.os.PowerManager;
 import android.os.SystemClock;
 import android.util.LocalLog;
+import android.util.Log;
 import android.util.Slog;
 
 import com.android.internal.annotations.VisibleForTesting;
@@ -57,6 +58,7 @@
     private LocalLog mLocalLog;
 
     private volatile boolean mDebug = false;
+    private volatile Object mLockWarning;
 
     private final ResponseQueue mResponseQueue;
 
@@ -107,6 +109,14 @@
         mDebug = debug;
     }
 
+    /**
+     * Yell loudly if someone tries making future {@link #execute(Command)} calls while holding a
+     * lock on the given object.
+     */
+    public void setLockWarning(Object lockWarning) {
+        mLockWarning = lockWarning;
+    }
+
     @Override
     public void run() {
         mCallbackHandler = new Handler(mLooper, this);
@@ -394,6 +404,10 @@
      */
     public NativeDaemonEvent[] executeForList(long timeoutMs, String cmd, Object... args)
             throws NativeDaemonConnectorException {
+        if (mLockWarning != null && Thread.holdsLock(mLockWarning)) {
+            Log.wtf(TAG, "Calling thread is holding lock " + mLockWarning, new Throwable());
+        }
+
         final long startTime = SystemClock.elapsedRealtime();
 
         final ArrayList<NativeDaemonEvent> events = Lists.newArrayList();
diff --git a/services/core/java/com/android/server/NetworkTimeUpdateService.java b/services/core/java/com/android/server/NetworkTimeUpdateService.java
index a0d305c..3f0664d 100644
--- a/services/core/java/com/android/server/NetworkTimeUpdateService.java
+++ b/services/core/java/com/android/server/NetworkTimeUpdateService.java
@@ -30,6 +30,7 @@
 import android.os.Looper;
 import android.os.Message;
 import android.os.SystemClock;
+import android.os.PowerManager;
 import android.provider.Settings;
 import android.util.Log;
 import android.util.NtpTrustedTime;
@@ -75,6 +76,7 @@
     private SettingsObserver mSettingsObserver;
     // The last time that we successfully fetched the NTP time.
     private long mLastNtpFetchTime = NOT_SET;
+    private final PowerManager.WakeLock mWakeLock;
 
     // Normal polling frequency
     private final long mPollingIntervalMs;
@@ -104,6 +106,9 @@
                 com.android.internal.R.integer.config_ntpRetry);
         mTimeErrorThresholdMs = mContext.getResources().getInteger(
                 com.android.internal.R.integer.config_ntpThreshold);
+
+        mWakeLock = ((PowerManager) context.getSystemService(Context.POWER_SERVICE)).newWakeLock(
+                PowerManager.PARTIAL_WAKE_LOCK, TAG);
     }
 
     /** Initialize the receivers and initiate the first NTP request */
@@ -148,7 +153,15 @@
     private void onPollNetworkTime(int event) {
         // If Automatic time is not set, don't bother.
         if (!isAutomaticTimeRequested()) return;
+        mWakeLock.acquire();
+        try {
+            onPollNetworkTimeUnderWakeLock(event);
+        } finally {
+            mWakeLock.release();
+        }
+    }
 
+    private void onPollNetworkTimeUnderWakeLock(int event) {
         final long refTime = SystemClock.elapsedRealtime();
         // If NITZ time was received less than mPollingIntervalMs time ago,
         // no need to sync to NTP.
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index df6b1d6..befaaef 100755
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -337,7 +337,7 @@
 
         ServiceRecord r = res.record;
 
-        if (!mAm.getUserManagerLocked().exists(r.userId)) {
+        if (!mAm.mUserController.exists(r.userId)) {
             Slog.d(TAG, "Trying to start service with non-existent user! " + r.userId);
             return null;
         }
@@ -1030,8 +1030,8 @@
         if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "retrieveServiceLocked: " + service
                 + " type=" + resolvedType + " callingUid=" + callingUid);
 
-        userId = mAm.handleIncomingUser(callingPid, callingUid, userId,
-                false, ActivityManagerService.ALLOW_NON_FULL_IN_PROFILE, "service", null);
+        userId = mAm.mUserController.handleIncomingUser(callingPid, callingUid, userId, false,
+                ActivityManagerService.ALLOW_NON_FULL_IN_PROFILE, "service", null);
 
         ServiceMap smap = getServiceMap(userId);
         final ComponentName comp = service.getComponent();
@@ -2333,7 +2333,8 @@
                 EventLog.writeEvent(EventLogTags.AM_SERVICE_CRASHED_TOO_MUCH,
                         sr.userId, sr.crashCount, sr.shortName, app.pid);
                 bringDownServiceLocked(sr);
-            } else if (!allowRestart || !mAm.isUserRunningLocked(sr.userId, false)) {
+            } else if (!allowRestart
+                    || !mAm.mUserController.isUserRunningLocked(sr.userId, false)) {
                 bringDownServiceLocked(sr);
             } else {
                 boolean canceled = scheduleServiceRestartLocked(sr, true);
@@ -2446,7 +2447,7 @@
             if (ActivityManager.checkUidPermission(
                     android.Manifest.permission.INTERACT_ACROSS_USERS_FULL,
                     uid) == PackageManager.PERMISSION_GRANTED) {
-                int[] users = mAm.getUsersLocked();
+                int[] users = mAm.mUserController.getUsers();
                 for (int ui=0; ui<users.length && res.size() < maxNum; ui++) {
                     ArrayMap<ComponentName, ServiceRecord> alls = getServices(users[ui]);
                     for (int i=0; i<alls.size() && res.size() < maxNum; i++) {
@@ -2580,7 +2581,7 @@
                 pw.print(mLastAnrDump);
                 pw.println();
             }
-            int[] users = mAm.getUsersLocked();
+            int[] users = mAm.mUserController.getUsers();
             for (int user : users) {
                 ServiceMap smap = getServiceMap(user);
                 boolean printed = false;
@@ -2817,7 +2818,7 @@
         ArrayList<ServiceRecord> services = new ArrayList<ServiceRecord>();
 
         synchronized (mAm) {
-            int[] users = mAm.getUsersLocked();
+            int[] users = mAm.mUserController.getUsers();
             if ("all".equals(name)) {
                 for (int user : users) {
                     ServiceMap smap = mServiceMap.get(user);
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 9a17f2f..ad95824 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -207,7 +207,6 @@
 import android.os.IBinder;
 import android.os.IPermissionController;
 import android.os.IProcessInfoService;
-import android.os.IUserManager;
 import android.os.Looper;
 import android.os.Message;
 import android.os.Parcel;
@@ -1271,8 +1270,6 @@
 
     final ActivityThread mSystemThread;
 
-    private UserManagerService mUserManager;
-
     private final class AppDeathRecipient implements IBinder.DeathRecipient {
         final ProcessRecord mApp;
         final int mPid;
@@ -1400,7 +1397,7 @@
                     boolean isBackground = (UserHandle.getAppId(proc.uid)
                             >= Process.FIRST_APPLICATION_UID
                             && proc.pid != MY_PID);
-                    for (int userId : mUserController.mCurrentProfileIds) {
+                    for (int userId : mUserController.getCurrentProfileIdsLocked()) {
                         isBackground &= (proc.userId != userId);
                     }
                     if (isBackground && !showBackground) {
@@ -1565,7 +1562,7 @@
                 break;
             }
             case START_USER_SWITCH_MSG: {
-                showUserSwitchDialog(msg.arg1, (String) msg.obj);
+                mUserController.showUserSwitchDialog(msg.arg1, (String) msg.obj);
                 break;
             }
             case DISMISS_DIALOG_MSG: {
@@ -3591,8 +3588,7 @@
 
     void enforceShellRestriction(String restriction, int userHandle) {
         if (Binder.getCallingUid() == Process.SHELL_UID) {
-            if (userHandle < 0
-                    || mUserManager.hasUserRestriction(restriction, userHandle)) {
+            if (userHandle < 0 || mUserController.hasUserRestriction(restriction, userHandle)) {
                 throw new SecurityException("Shell does not have permission to access user "
                         + userHandle);
             }
@@ -3854,8 +3850,8 @@
             Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
             int startFlags, ProfilerInfo profilerInfo, Bundle options, int userId) {
         enforceNotIsolatedCaller("startActivity");
-        userId = handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), userId,
-                false, ALLOW_FULL_ONLY, "startActivity", null);
+        userId = mUserController.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
+                userId, false, ALLOW_FULL_ONLY, "startActivity", null);
         // TODO: Switch to user app stacks here.
         return mStackSupervisor.startActivityMayWait(caller, -1, callingPackage, intent,
                 resolvedType, null, null, resultTo, resultWho, requestCode, startFlags,
@@ -3945,8 +3941,8 @@
             Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
             int startFlags, ProfilerInfo profilerInfo, Bundle options, int userId) {
         enforceNotIsolatedCaller("startActivityAndWait");
-        userId = handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), userId,
-                false, ALLOW_FULL_ONLY, "startActivityAndWait", null);
+        userId = mUserController.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
+                userId, false, ALLOW_FULL_ONLY, "startActivityAndWait", null);
         WaitResult res = new WaitResult();
         // TODO: Switch to user app stacks here.
         mStackSupervisor.startActivityMayWait(caller, -1, callingPackage, intent, resolvedType,
@@ -3960,8 +3956,8 @@
             Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
             int startFlags, Configuration config, Bundle options, int userId) {
         enforceNotIsolatedCaller("startActivityWithConfig");
-        userId = handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), userId,
-                false, ALLOW_FULL_ONLY, "startActivityWithConfig", null);
+        userId = mUserController.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
+                userId, false, ALLOW_FULL_ONLY, "startActivityWithConfig", null);
         // TODO: Switch to user app stacks here.
         int ret = mStackSupervisor.startActivityMayWait(caller, -1, callingPackage, intent,
                 resolvedType, null, null, resultTo, resultWho, requestCode, startFlags,
@@ -4018,8 +4014,8 @@
         if (session == null || interactor == null) {
             throw new NullPointerException("null session or interactor");
         }
-        userId = handleIncomingUser(callingPid, callingUid, userId,
-                false, ALLOW_FULL_ONLY, "startVoiceActivity", null);
+        userId = mUserController.handleIncomingUser(callingPid, callingUid, userId, false,
+                ALLOW_FULL_ONLY, "startVoiceActivity", null);
         // TODO: Switch to user app stacks here.
         return mStackSupervisor.startActivityMayWait(null, callingUid, callingPackage, intent,
                 resolvedType, session, interactor, null, null, 0, startFlags, profilerInfo, null,
@@ -4207,8 +4203,8 @@
             String resultWho, int requestCode, int startFlags, Bundle options, int userId,
             IActivityContainer container, TaskRecord inTask) {
 
-        userId = handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), userId,
-                false, ALLOW_FULL_ONLY, "startActivityInPackage", null);
+        userId = mUserController.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
+                userId, false, ALLOW_FULL_ONLY, "startActivityInPackage", null);
 
         // TODO: Switch to user app stacks here.
         int ret = mStackSupervisor.startActivityMayWait(null, uid, callingPackage, intent,
@@ -4222,8 +4218,8 @@
             Intent[] intents, String[] resolvedTypes, IBinder resultTo, Bundle options,
             int userId) {
         enforceNotIsolatedCaller("startActivities");
-        userId = handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), userId,
-                false, ALLOW_FULL_ONLY, "startActivity", null);
+        userId = mUserController.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
+                userId, false, ALLOW_FULL_ONLY, "startActivity", null);
         // TODO: Switch to user app stacks here.
         int ret = mStackSupervisor.startActivities(caller, -1, callingPackage, intents,
                 resolvedTypes, resultTo, options, userId);
@@ -4234,8 +4230,8 @@
             Intent[] intents, String[] resolvedTypes, IBinder resultTo,
             Bundle options, int userId) {
 
-        userId = handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), userId,
-                false, ALLOW_FULL_ONLY, "startActivityInPackage", null);
+        userId = mUserController.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
+                userId, false, ALLOW_FULL_ONLY, "startActivityInPackage", null);
         // TODO: Switch to user app stacks here.
         int ret = mStackSupervisor.startActivities(null, uid, callingPackage, intents, resolvedTypes,
                 resultTo, options, userId);
@@ -5136,8 +5132,8 @@
         }
         int uid = Binder.getCallingUid();
         int pid = Binder.getCallingPid();
-        userId = handleIncomingUser(pid, uid,
-                userId, false, ALLOW_FULL_ONLY, "clearApplicationUserData", null);
+        userId = mUserController.handleIncomingUser(pid, uid, userId, false,
+                ALLOW_FULL_ONLY, "clearApplicationUserData", null);
         long callingId = Binder.clearCallingIdentity();
         try {
             IPackageManager pm = AppGlobals.getPackageManager();
@@ -5216,7 +5212,7 @@
             throw new SecurityException(msg);
         }
 
-        userId = handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
+        userId = mUserController.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
                 userId, true, ALLOW_FULL_ONLY, "killBackgroundProcesses", null);
         long callingId = Binder.clearCallingIdentity();
         try {
@@ -5299,14 +5295,14 @@
             throw new SecurityException(msg);
         }
         final int callingPid = Binder.getCallingPid();
-        userId = handleIncomingUser(callingPid, Binder.getCallingUid(),
+        userId = mUserController.handleIncomingUser(callingPid, Binder.getCallingUid(),
                 userId, true, ALLOW_FULL_ONLY, "forceStopPackage", null);
         long callingId = Binder.clearCallingIdentity();
         try {
             IPackageManager pm = AppGlobals.getPackageManager();
             synchronized(this) {
                 int[] users = userId == UserHandle.USER_ALL
-                        ? getUsersLocked() : new int[] { userId };
+                        ? mUserController.getUsers() : new int[] { userId };
                 for (int user : users) {
                     int pkgUid = -1;
                     try {
@@ -5324,7 +5320,7 @@
                         Slog.w(TAG, "Failed trying to unstop package "
                                 + packageName + ": " + e);
                     }
-                    if (isUserRunningLocked(user, false)) {
+                    if (mUserController.isUserRunningLocked(user, false)) {
                         forceStopPackageLocked(packageName, pkgUid, "from pid " + callingPid);
                     }
                 }
@@ -6662,7 +6658,7 @@
         synchronized(this) {
             int callingUid = Binder.getCallingUid();
             int origUserId = userId;
-            userId = handleIncomingUser(Binder.getCallingPid(), callingUid, userId,
+            userId = mUserController.handleIncomingUser(Binder.getCallingPid(), callingUid, userId,
                     type == ActivityManager.INTENT_SENDER_BROADCAST,
                     ALLOW_NON_FULL, "getIntentSender", null);
             if (origUserId == UserHandle.USER_CURRENT) {
@@ -7910,8 +7906,9 @@
     @Override
     public void grantUriPermissionFromOwner(IBinder token, int fromUid, String targetPkg, Uri uri,
             final int modeFlags, int sourceUserId, int targetUserId) {
-        targetUserId = handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
-                targetUserId, false, ALLOW_FULL_ONLY, "grantUriPermissionFromOwner", null);
+        targetUserId = mUserController.handleIncomingUser(Binder.getCallingPid(),
+                Binder.getCallingUid(), targetUserId, false, ALLOW_FULL_ONLY,
+                "grantUriPermissionFromOwner", null);
         synchronized(this) {
             UriPermissionOwner owner = UriPermissionOwner.fromExternalToken(token);
             if (owner == null) {
@@ -8418,7 +8415,7 @@
     @Override
     public List<ActivityManager.RecentTaskInfo> getRecentTasks(int maxNum, int flags, int userId) {
         final int callingUid = Binder.getCallingUid();
-        userId = handleIncomingUser(Binder.getCallingPid(), callingUid, userId,
+        userId = mUserController.handleIncomingUser(Binder.getCallingPid(), callingUid, userId,
                 false, ALLOW_FULL_ONLY, "getRecentTasks", null);
 
         final boolean includeProfiles = (flags & ActivityManager.RECENT_INCLUDE_PROFILES) != 0;
@@ -8436,7 +8433,7 @@
 
             final Set<Integer> includedUsers;
             if (includeProfiles) {
-                includedUsers = getProfileIdsLocked(userId);
+                includedUsers = mUserController.getProfileIds(userId);
             } else {
                 includedUsers = new HashSet<>();
             }
@@ -9458,16 +9455,15 @@
         boolean checkedGrants = false;
         if (checkUser) {
             // Looking for cross-user grants before enforcing the typical cross-users permissions
-            int tmpTargetUserId = unsafeConvertIncomingUserLocked(userId);
+            int tmpTargetUserId = mUserController.unsafeConvertIncomingUserLocked(userId);
             if (tmpTargetUserId != UserHandle.getUserId(callingUid)) {
                 if (checkAuthorityGrants(callingUid, cpi, tmpTargetUserId, checkUser)) {
                     return null;
                 }
                 checkedGrants = true;
             }
-            userId = handleIncomingUser(callingPid, callingUid, userId,
-                    false, ALLOW_NON_FULL,
-                    "checkContentProviderPermissionLocked " + cpi.authority, null);
+            userId = mUserController.handleIncomingUser(callingPid, callingUid, userId, false,
+                    ALLOW_NON_FULL, "checkContentProviderPermissionLocked " + cpi.authority, null);
             if (userId != tmpTargetUserId) {
                 // When we actually went to determine the final targer user ID, this ended
                 // up different than our initial check for the authority.  This is because
@@ -9806,7 +9802,7 @@
 
                 // Make sure that the user who owns this provider is running.  If not,
                 // we don't want to allow it to run.
-                if (!isUserRunningLocked(userId, false)) {
+                if (!mUserController.isUserRunningLocked(userId, false)) {
                     Slog.w(TAG, "Unable to launch app "
                             + cpi.applicationInfo.packageName + "/"
                             + cpi.applicationInfo.uid + " for provider "
@@ -9992,8 +9988,8 @@
             String name, int userId, IBinder token) {
         enforceCallingPermission(android.Manifest.permission.ACCESS_CONTENT_PROVIDERS_EXTERNALLY,
             "Do not have permission in call getContentProviderExternal()");
-        userId = handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), userId,
-                false, ALLOW_FULL_ONLY, "getContentProvider", null);
+        userId = mUserController.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
+                userId, false, ALLOW_FULL_ONLY, "getContentProvider", null);
         return getContentProviderExternalUnchecked(name, token, userId);
     }
 
@@ -10305,7 +10301,7 @@
         long ident = 0;
         boolean clearedIdentity = false;
         synchronized (this) {
-            userId = unsafeConvertIncomingUserLocked(userId);
+            userId = mUserController.unsafeConvertIncomingUserLocked(userId);
         }
         if (canClearIdentity(callingPid, callingUid, userId)) {
             clearedIdentity = true;
@@ -10975,7 +10971,7 @@
     public boolean isAssistDataAllowedOnCurrentActivity() {
         int userId;
         synchronized (this) {
-            userId = mUserController.mCurrentUserId;
+            userId = mUserController.getCurrentUserIdLocked();
             ActivityRecord activity = getFocusedStack().topActivity();
             if (activity == null) {
                 return false;
@@ -11890,7 +11886,7 @@
         }
 
         // TODO: can we still do this with per user encryption?
-        final int[] users = getUsersLocked();
+        final int[] users = mUserController.getUsers();
         if (users.length <= 0) {
             return false;
         }
@@ -11920,8 +11916,7 @@
             mUserController.updateCurrentProfileIdsLocked();
 
             mRecentTasks.clear();
-            mRecentTasks.addAll(mTaskPersister.restoreTasksLocked(
-                    getUserManagerLocked().getUserIds()));
+            mRecentTasks.addAll(mTaskPersister.restoreTasksLocked(mUserController.getUserIds()));
             mRecentTasks.cleanupLocked(UserHandle.USER_ALL);
             mTaskPersister.startPersisting();
 
@@ -12026,7 +12021,7 @@
         loadResourcesOnSystemReady();
         final int currentUserId;
         synchronized (this) {
-            currentUserId = mUserController.mCurrentUserId;
+            currentUserId = mUserController.getCurrentUserIdLocked();
             readGrantedUriPermissionsLocked();
         }
 
@@ -12110,7 +12105,7 @@
                 Binder.restoreCallingIdentity(ident);
             }
             mStackSupervisor.resumeTopActivitiesLocked();
-            sendUserSwitchBroadcastsLocked(-1, currentUserId);
+            mUserController.sendUserSwitchBroadcastsLocked(-1, currentUserId);
         }
     }
 
@@ -12310,7 +12305,7 @@
         // launching the report UI under a different user.
         app.errorReportReceiver = null;
 
-        for (int userId : mUserController.mCurrentProfileIds) {
+        for (int userId : mUserController.getCurrentProfileIdsLocked()) {
             if (app.userId == userId) {
                 app.errorReportReceiver = ApplicationErrorReport.getErrorReportReceiver(
                         mContext, app.info.packageName, app.info.flags);
@@ -16031,97 +16026,10 @@
     @Override
     public int handleIncomingUser(int callingPid, int callingUid, int userId, boolean allowAll,
             boolean requireFull, String name, String callerPackage) {
-        return handleIncomingUser(callingPid, callingUid, userId, allowAll,
+        return mUserController.handleIncomingUser(callingPid, callingUid, userId, allowAll,
                 requireFull ? ALLOW_FULL_ONLY : ALLOW_NON_FULL, name, callerPackage);
     }
 
-    int unsafeConvertIncomingUserLocked(int userId) {
-        return (userId == UserHandle.USER_CURRENT || userId == UserHandle.USER_CURRENT_OR_SELF)
-                ? mUserController.mCurrentUserId : userId;
-    }
-
-    int handleIncomingUser(int callingPid, int callingUid, int userId, boolean allowAll,
-            int allowMode, String name, String callerPackage) {
-        final int callingUserId = UserHandle.getUserId(callingUid);
-        if (callingUserId == userId) {
-            return userId;
-        }
-
-        // Note that we may be accessing mCurrentUserId outside of a lock...
-        // shouldn't be a big deal, if this is being called outside
-        // of a locked context there is intrinsically a race with
-        // the value the caller will receive and someone else changing it.
-        // We assume that USER_CURRENT_OR_SELF will use the current user; later
-        // we will switch to the calling user if access to the current user fails.
-        int targetUserId = unsafeConvertIncomingUserLocked(userId);
-
-        if (callingUid != 0 && callingUid != Process.SYSTEM_UID) {
-            final boolean allow;
-            if (checkComponentPermission(INTERACT_ACROSS_USERS_FULL, callingPid,
-                    callingUid, -1, true) == PackageManager.PERMISSION_GRANTED) {
-                // If the caller has this permission, they always pass go.  And collect $200.
-                allow = true;
-            } else if (allowMode == ALLOW_FULL_ONLY) {
-                // We require full access, sucks to be you.
-                allow = false;
-            } else if (checkComponentPermission(INTERACT_ACROSS_USERS, callingPid,
-                    callingUid, -1, true) != PackageManager.PERMISSION_GRANTED) {
-                // If the caller does not have either permission, they are always doomed.
-                allow = false;
-            } else if (allowMode == ALLOW_NON_FULL) {
-                // We are blanket allowing non-full access, you lucky caller!
-                allow = true;
-            } else if (allowMode == ALLOW_NON_FULL_IN_PROFILE) {
-                // We may or may not allow this depending on whether the two users are
-                // in the same profile.
-                allow = mUserController.isSameProfileGroup(callingUserId, targetUserId);
-            } else {
-                throw new IllegalArgumentException("Unknown mode: " + allowMode);
-            }
-            if (!allow) {
-                if (userId == UserHandle.USER_CURRENT_OR_SELF) {
-                    // In this case, they would like to just execute as their
-                    // owner user instead of failing.
-                    targetUserId = callingUserId;
-                } else {
-                    StringBuilder builder = new StringBuilder(128);
-                    builder.append("Permission Denial: ");
-                    builder.append(name);
-                    if (callerPackage != null) {
-                        builder.append(" from ");
-                        builder.append(callerPackage);
-                    }
-                    builder.append(" asks to run as user ");
-                    builder.append(userId);
-                    builder.append(" but is calling from user ");
-                    builder.append(UserHandle.getUserId(callingUid));
-                    builder.append("; this requires ");
-                    builder.append(INTERACT_ACROSS_USERS_FULL);
-                    if (allowMode != ALLOW_FULL_ONLY) {
-                        builder.append(" or ");
-                        builder.append(INTERACT_ACROSS_USERS);
-                    }
-                    String msg = builder.toString();
-                    Slog.w(TAG, msg);
-                    throw new SecurityException(msg);
-                }
-            }
-        }
-        if (!allowAll && targetUserId < 0) {
-            throw new IllegalArgumentException(
-                    "Call does not support special user #" + targetUserId);
-        }
-        // Check shell permission
-        if (callingUid == Process.SHELL_UID && targetUserId >= UserHandle.USER_SYSTEM) {
-            if (mUserManager.hasUserRestriction(UserManager.DISALLOW_DEBUGGING_FEATURES,
-                    targetUserId)) {
-                throw new SecurityException("Shell does not have permission to access user "
-                        + targetUserId + "\n " + Debug.getCallers(3));
-            }
-        }
-        return targetUserId;
-    }
-
     boolean isSingleton(String componentProcessName, ApplicationInfo aInfo,
             String className, int flags) {
         boolean result = false;
@@ -16434,8 +16342,8 @@
                 callingPid = Binder.getCallingPid();
             }
 
-            userId = handleIncomingUser(callingPid, callingUid, userId,
-                    true, ALLOW_FULL_ONLY, "registerReceiver", callerPackage);
+            userId = mUserController.handleIncomingUser(callingPid, callingUid, userId, true,
+                    ALLOW_FULL_ONLY, "registerReceiver", callerPackage);
 
             Iterator<String> actions = filter.actionsIterator();
             if (actions == null) {
@@ -16625,8 +16533,8 @@
             for (int user : users) {
                 // Skip users that have Shell restrictions
                 if (callingUid == Process.SHELL_UID
-                        && getUserManagerLocked().hasUserRestriction(
-                                UserManager.DISALLOW_DEBUGGING_FEATURES, user)) {
+                        && mUserController.hasUserRestriction(
+                        UserManager.DISALLOW_DEBUGGING_FEATURES, user)) {
                     continue;
                 }
                 List<ResolveInfo> newReceivers = AppGlobals.getPackageManager()
@@ -16715,14 +16623,14 @@
             Slog.w(TAG, "Broadcast " + intent + " not ordered but result callback requested!");
         }
 
-        userId = handleIncomingUser(callingPid, callingUid, userId,
-                true, ALLOW_NON_FULL, "broadcast", callerPackage);
+        userId = mUserController.handleIncomingUser(callingPid, callingUid, userId, true,
+                ALLOW_NON_FULL, "broadcast", callerPackage);
 
         // Make sure that the user who is receiving this broadcast is running.
         // If not, we will just skip it. Make an exception for shutdown broadcasts
         // and upgrade steps.
 
-        if (userId != UserHandle.USER_ALL && !isUserRunningLocked(userId, false)) {
+        if (userId != UserHandle.USER_ALL && !mUserController.isUserRunningLocked(userId, false)) {
             if ((callingUid != Process.SYSTEM_UID
                     || (intent.getFlags() & Intent.FLAG_RECEIVER_BOOT_UPGRADE) == 0)
                     && !Intent.ACTION_SHUTDOWN.equals(intent.getAction())) {
@@ -17027,9 +16935,8 @@
         if (intent.getComponent() == null) {
             if (userId == UserHandle.USER_ALL && callingUid == Process.SHELL_UID) {
                 // Query one target user at a time, excluding shell-restricted users
-                UserManagerService ums = getUserManagerLocked();
                 for (int i = 0; i < users.length; i++) {
-                    if (ums.hasUserRestriction(
+                    if (mUserController.hasUserRestriction(
                             UserManager.DISALLOW_DEBUGGING_FEATURES, users[i])) {
                         continue;
                     }
@@ -17247,7 +17154,7 @@
             throw new IllegalArgumentException("File descriptors passed in Intent");
         }
 
-        userId = handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
+        userId = mUserController.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
                 userId, true, ALLOW_NON_FULL, "removeStickyBroadcast", null);
 
         synchronized(this) {
@@ -17331,7 +17238,7 @@
             IInstrumentationWatcher watcher, IUiAutomationConnection uiAutomationConnection,
             int userId, String abiOverride) {
         enforceNotIsolatedCaller("startInstrumentation");
-        userId = handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
+        userId = mUserController.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
                 userId, false, ALLOW_FULL_ONLY, "startInstrumentation", null);
         // Refuse possible leaked file descriptors
         if (arguments != null && arguments.hasFileDescriptors()) {
@@ -17597,10 +17504,11 @@
             Binder.restoreCallingIdentity(origId);
         }
     }
+
     void updateUserConfigurationLocked() {
         Configuration configuration = new Configuration(mConfiguration);
         Settings.System.getConfigurationForUser(mContext.getContentResolver(), configuration,
-                mUserController.mCurrentUserId);
+                mUserController.getCurrentUserIdLocked());
         updateConfigurationLocked(configuration, null, false);
     }
 
@@ -17649,7 +17557,7 @@
                 mConfiguration = newConfig;
                 Slog.i(TAG, "Config changes=" + Integer.toHexString(changes) + " " + newConfig);
                 mUsageStatsService.reportConfigurationChange(newConfig,
-                        mUserController.mCurrentUserId);
+                        mUserController.getCurrentUserIdLocked());
                 //mUsageStatsService.noteStartConfig(newConfig);
 
                 final Configuration configCopy = new Configuration(mConfiguration);
@@ -19133,7 +19041,7 @@
             String authority) {
         if (app == null) return;
         if (app.curProcState <= ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND) {
-            UserState userState = mUserController.getStartedUserState(app.userId);
+            UserState userState = mUserController.getStartedUserStateLocked(app.userId);
             if (userState == null) return;
             final long now = SystemClock.elapsedRealtime();
             Long lastReported = userState.mProviderLastReportedFg.get(authority);
@@ -19855,7 +19763,7 @@
     }
 
     private ProcessRecord findProcessLocked(String process, int userId, String callName) {
-        userId = handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
+        userId = mUserController.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
                 userId, true, ALLOW_FULL_ONLY, callName, null);
         ProcessRecord proc = null;
         try {
@@ -20016,31 +19924,12 @@
         return mUserController.startUser(userId, /* foreground */ false);
     }
 
-    /**
-     * Start user, if its not already running, and bring it to foreground.
-     */
-    boolean startUserInForeground(final int userId, Dialog dlg) {
-        boolean result = mUserController.startUser(userId, /* foreground */ true);
-        dlg.dismiss();
-        return result;
-    }
-
-    private Set<Integer> getProfileIdsLocked(int userId) {
-        Set<Integer> userIds = new HashSet<Integer>();
-        final List<UserInfo> profiles = getUserManagerLocked().getProfiles(
-                userId, false /* enabledOnly */);
-        for (UserInfo user : profiles) {
-            userIds.add(Integer.valueOf(user.id));
-        }
-        return userIds;
-    }
-
     @Override
     public boolean switchUser(final int userId) {
         enforceShellRestriction(UserManager.DISALLOW_DEBUGGING_FEATURES, userId);
         String userName;
         synchronized (this) {
-            UserInfo userInfo = getUserManagerLocked().getUserInfo(userId);
+            UserInfo userInfo = mUserController.getUserInfo(userId);
             if (userInfo == null) {
                 Slog.w(TAG, "No user info for user #" + userId);
                 return false;
@@ -20050,68 +19939,13 @@
                 return false;
             }
             userName = userInfo.name;
-            mUserController.mTargetUserId = userId;
+            mUserController.setTargetUserIdLocked(userId);
         }
         mUiHandler.removeMessages(START_USER_SWITCH_MSG);
         mUiHandler.sendMessage(mUiHandler.obtainMessage(START_USER_SWITCH_MSG, userId, 0, userName));
         return true;
     }
 
-    private void showUserSwitchDialog(int userId, String userName) {
-        // The dialog will show and then initiate the user switch by calling startUserInForeground
-        Dialog d = new UserSwitchingDialog(this, mContext, userId, userName,
-                true /* above system */);
-        d.show();
-    }
-
-    void sendUserSwitchBroadcastsLocked(int oldUserId, int newUserId) {
-        long ident = Binder.clearCallingIdentity();
-        try {
-            Intent intent;
-            if (oldUserId >= 0) {
-                // Send USER_BACKGROUND broadcast to all profiles of the outgoing user
-                List<UserInfo> profiles = mUserManager.getProfiles(oldUserId, false);
-                int count = profiles.size();
-                for (int i = 0; i < count; i++) {
-                    int profileUserId = profiles.get(i).id;
-                    intent = new Intent(Intent.ACTION_USER_BACKGROUND);
-                    intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
-                            | Intent.FLAG_RECEIVER_FOREGROUND);
-                    intent.putExtra(Intent.EXTRA_USER_HANDLE, profileUserId);
-                    broadcastIntentLocked(null, null, intent,
-                            null, null, 0, null, null, null, AppOpsManager.OP_NONE,
-                            null, false, false, MY_PID, Process.SYSTEM_UID, profileUserId);
-                }
-            }
-            if (newUserId >= 0) {
-                // Send USER_FOREGROUND broadcast to all profiles of the incoming user
-                List<UserInfo> profiles = mUserManager.getProfiles(newUserId, false);
-                int count = profiles.size();
-                for (int i = 0; i < count; i++) {
-                    int profileUserId = profiles.get(i).id;
-                    intent = new Intent(Intent.ACTION_USER_FOREGROUND);
-                    intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
-                            | Intent.FLAG_RECEIVER_FOREGROUND);
-                    intent.putExtra(Intent.EXTRA_USER_HANDLE, profileUserId);
-                    broadcastIntentLocked(null, null, intent,
-                            null, null, 0, null, null, null, AppOpsManager.OP_NONE,
-                            null, false, false, MY_PID, Process.SYSTEM_UID, profileUserId);
-                }
-                intent = new Intent(Intent.ACTION_USER_SWITCHED);
-                intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
-                        | Intent.FLAG_RECEIVER_FOREGROUND);
-                intent.putExtra(Intent.EXTRA_USER_HANDLE, newUserId);
-                broadcastIntentLocked(null, null, intent,
-                        null, null, 0, null, null,
-                        new String[] {android.Manifest.permission.MANAGE_USERS},
-                        AppOpsManager.OP_NONE, null, false, false, MY_PID, Process.SYSTEM_UID,
-                        UserHandle.USER_ALL);
-            }
-        } finally {
-            Binder.restoreCallingIdentity(ident);
-        }
-    }
-
     void scheduleStartProfilesLocked() {
         if (!mHandler.hasMessages(START_PROFILES_MSG)) {
             mHandler.sendMessageDelayed(mHandler.obtainMessage(START_PROFILES_MSG),
@@ -20145,22 +19979,10 @@
             throw new SecurityException(msg);
         }
         synchronized (this) {
-            return isUserRunningLocked(userId, orStopped);
+            return mUserController.isUserRunningLocked(userId, orStopped);
         }
     }
 
-    boolean isUserRunningLocked(int userId, boolean orStopped) {
-        UserState state = mUserController.getStartedUserState(userId);
-        if (state == null) {
-            return false;
-        }
-        if (orStopped) {
-            return true;
-        }
-        return state.mState != UserState.STATE_STOPPING
-                && state.mState != UserState.STATE_SHUTDOWN;
-    }
-
     @Override
     public int[] getRunningUserIds() {
         if (checkCallingPermission(INTERACT_ACROSS_USERS)
@@ -20187,19 +20009,6 @@
         mUserController.unregisterUserSwitchObserver(observer);
     }
 
-    int[] getUsersLocked() {
-        UserManagerService ums = getUserManagerLocked();
-        return ums != null ? ums.getUserIds() : new int[] { 0 };
-    }
-
-    UserManagerService getUserManagerLocked() {
-        if (mUserManager == null) {
-            IBinder b = ServiceManager.getService(Context.USER_SERVICE);
-            mUserManager = (UserManagerService)IUserManager.Stub.asInterface(b);
-        }
-        return mUserManager;
-    }
-
     private int applyUserId(int uid, int userId) {
         return UserHandle.getUid(userId, uid);
     }
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 4897eb9..eb79ae7 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -362,7 +362,7 @@
         mHandler = new ActivityStackHandler(mService.mHandler.getLooper());
         mWindowManager = mService.mWindowManager;
         mStackId = activityContainer.mStackId;
-        mCurrentUser = mService.mUserController.mCurrentUserId;
+        mCurrentUser = mService.mUserController.getCurrentUserIdLocked();
         mRecentTasks = recentTasks;
         mTaskPositioner = mStackId == FREEFORM_WORKSPACE_STACK_ID
                 ? new LaunchingTaskPositioner() : null;
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 7e42dce..0afc715 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -4671,7 +4671,7 @@
         @Override
         public final int startActivity(Intent intent) {
             mService.enforceNotIsolatedCaller("ActivityContainer.startActivity");
-            final int userId = mService.handleIncomingUser(Binder.getCallingPid(),
+            final int userId = mService.mUserController.handleIncomingUser(Binder.getCallingPid(),
                     Binder.getCallingUid(), mCurrentUser, false,
                     ActivityManagerService.ALLOW_FULL_ONLY, "ActivityContainer", null);
 
@@ -4697,7 +4697,7 @@
                 throw new IllegalArgumentException("Bad PendingIntent object");
             }
 
-            final int userId = mService.handleIncomingUser(Binder.getCallingPid(),
+            final int userId = mService.mUserController.handleIncomingUser(Binder.getCallingPid(),
                     Binder.getCallingUid(), mCurrentUser, false,
                     ActivityManagerService.ALLOW_FULL_ONLY, "ActivityContainer", null);
 
diff --git a/services/core/java/com/android/server/am/PendingIntentRecord.java b/services/core/java/com/android/server/am/PendingIntentRecord.java
index 6ed880e..8039072 100644
--- a/services/core/java/com/android/server/am/PendingIntentRecord.java
+++ b/services/core/java/com/android/server/am/PendingIntentRecord.java
@@ -248,7 +248,7 @@
                 boolean sendFinish = finishedReceiver != null;
                 int userId = key.userId;
                 if (userId == UserHandle.USER_CURRENT) {
-                    userId = owner.mUserController.getCurrentUserIdLocked();
+                    userId = owner.mUserController.getCurrentOrTargetUserIdLocked();
                 }
                 switch (key.type) {
                     case ActivityManager.INTENT_SENDER_ACTIVITY:
diff --git a/services/core/java/com/android/server/am/RecentTasks.java b/services/core/java/com/android/server/am/RecentTasks.java
index edd16ef..862a973 100644
--- a/services/core/java/com/android/server/am/RecentTasks.java
+++ b/services/core/java/com/android/server/am/RecentTasks.java
@@ -108,7 +108,7 @@
 
         final IPackageManager pm = AppGlobals.getPackageManager();
         final int[] users = (userId == UserHandle.USER_ALL)
-                ? mService.getUsersLocked() : new int[] { userId };
+                ? mService.mUserController.getUsers() : new int[] { userId };
         for (int userIdx = 0; userIdx < users.length; userIdx++) {
             final int user = users[userIdx];
             recentsCount = size() - 1;
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index ff74d83..4085489 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -18,11 +18,17 @@
 
 import static android.Manifest.permission.INTERACT_ACROSS_USERS;
 import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
+
 import static android.app.ActivityManager.USER_OP_IS_CURRENT;
 import static android.app.ActivityManager.USER_OP_SUCCESS;
+import static android.os.Process.SYSTEM_UID;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_MU;
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
+import static com.android.server.am.ActivityManagerService.ALLOW_FULL_ONLY;
+import static com.android.server.am.ActivityManagerService.ALLOW_NON_FULL;
+import static com.android.server.am.ActivityManagerService.ALLOW_NON_FULL_IN_PROFILE;
+import static com.android.server.am.ActivityManagerService.MY_PID;
 import static com.android.server.am.ActivityManagerService.REPORT_USER_SWITCH_COMPLETE_MSG;
 import static com.android.server.am.ActivityManagerService.REPORT_USER_SWITCH_MSG;
 import static com.android.server.am.ActivityManagerService.SYSTEM_USER_CURRENT_MSG;
@@ -31,8 +37,10 @@
 
 import android.app.ActivityManager;
 import android.app.AppOpsManager;
+import android.app.Dialog;
 import android.app.IStopUserCallback;
 import android.app.IUserSwitchObserver;
+import android.content.Context;
 import android.content.IIntentReceiver;
 import android.content.Intent;
 import android.content.pm.PackageManager;
@@ -40,11 +48,15 @@
 import android.os.BatteryStats;
 import android.os.Binder;
 import android.os.Bundle;
+import android.os.Debug;
 import android.os.Handler;
+import android.os.IBinder;
 import android.os.IRemoteCallback;
+import android.os.IUserManager;
 import android.os.Process;
 import android.os.RemoteCallbackList;
 import android.os.RemoteException;
+import android.os.ServiceManager;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.util.Slog;
@@ -58,7 +70,9 @@
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.HashSet;
 import java.util.List;
+import java.util.Set;
 
 /**
  * Helper class for {@link ActivityManagerService} responsible for multi-user functionality.
@@ -76,9 +90,9 @@
     private final Handler mHandler;
 
     // Holds the current foreground user's id
-    int mCurrentUserId = 0;
+    private int mCurrentUserId = UserHandle.USER_SYSTEM;
     // Holds the target user's id during a user switch
-    int mTargetUserId = UserHandle.USER_NULL;
+    private int mTargetUserId = UserHandle.USER_NULL;
 
     /**
      * Which users have been started, so are allowed to run code.
@@ -96,7 +110,7 @@
 
     // If there are multiple profiles for the current user, their ids are here
     // Currently only the primary user can have managed profiles
-    int[] mCurrentProfileIds = new int[] {}; // Accessed by ActivityStack
+    private int[] mCurrentProfileIds = new int[] {};
 
     /**
      * Mapping from each known user ID to the profile group ID it is associated with.
@@ -106,7 +120,7 @@
     /**
      * Registered observers of the user switching mechanics.
      */
-    final RemoteCallbackList<IUserSwitchObserver> mUserSwitchObservers
+    private final RemoteCallbackList<IUserSwitchObserver> mUserSwitchObservers
             = new RemoteCallbackList<>();
 
     /**
@@ -114,6 +128,8 @@
      */
     Object mCurUserSwitchCallback;
 
+    private volatile UserManagerService mUserManager;
+
     UserController(ActivityManagerService service) {
         mService = service;
         mHandler = mService.mHandler;
@@ -176,8 +192,7 @@
                 mService.broadcastIntentLocked(null, null, intent,
                         null, null, 0, null, null,
                         new String[]{android.Manifest.permission.RECEIVE_BOOT_COMPLETED},
-                        AppOpsManager.OP_NONE, null, true, false, ActivityManagerService.MY_PID,
-                        Process.SYSTEM_UID, userId);
+                        AppOpsManager.OP_NONE, null, true, false, MY_PID, SYSTEM_UID, userId);
             }
         }
     }
@@ -272,16 +287,14 @@
                         mService.mSystemServiceManager.stopUser(userId);
                         mService.broadcastIntentLocked(null, null, shutdownIntent,
                                 null, shutdownReceiver, 0, null, null, null, AppOpsManager.OP_NONE,
-                                null, true, false, ActivityManagerService.MY_PID,
-                                android.os.Process.SYSTEM_UID, userId);
+                                null, true, false, MY_PID, SYSTEM_UID, userId);
                     }
                 };
                 // Kick things off.
                 mService.broadcastIntentLocked(null, null, stoppingIntent,
                         null, stoppingReceiver, 0, null, null,
                         new String[]{INTERACT_ACROSS_USERS}, AppOpsManager.OP_NONE,
-                        null, true, false, ActivityManagerService.MY_PID, Process.SYSTEM_UID,
-                        UserHandle.USER_ALL);
+                        null, true, false, MY_PID, SYSTEM_UID, UserHandle.USER_ALL);
             } finally {
                 Binder.restoreCallingIdentity(ident);
             }
@@ -338,8 +351,7 @@
         intent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
         mService.broadcastIntentLocked(null, null, intent,
                 null, null, 0, null, null, null, AppOpsManager.OP_NONE,
-                null, false, false, ActivityManagerService.MY_PID, Process.SYSTEM_UID,
-                UserHandle.USER_ALL);
+                null, false, false, MY_PID, SYSTEM_UID, UserHandle.USER_ALL);
     }
 
 
@@ -357,7 +369,7 @@
                         || oldUss.mState == UserState.STATE_SHUTDOWN) {
                     continue;
                 }
-                UserInfo userInfo = getUserManagerLocked().getUserInfo(oldUserId);
+                UserInfo userInfo = getUserInfo(oldUserId);
                 if (userInfo.isGuest()) {
                     // This is a user to be stopped.
                     stopUserLocked(oldUserId, null);
@@ -369,7 +381,7 @@
 
     void startProfilesLocked() {
         if (DEBUG_MU) Slog.i(TAG, "startProfilesLocked");
-        List<UserInfo> profiles = getUserManagerLocked().getProfiles(
+        List<UserInfo> profiles = getUserManager().getProfiles(
                 mCurrentUserId, false /* enabledOnly */);
         List<UserInfo> profilesToStart = new ArrayList<>(profiles.size());
         for (UserInfo user : profiles) {
@@ -388,8 +400,13 @@
         }
     }
 
-    private UserManagerService getUserManagerLocked() {
-        return mService.getUserManagerLocked();
+    private UserManagerService getUserManager() {
+        UserManagerService userManager = mUserManager;
+        if (userManager == null) {
+            IBinder b = ServiceManager.getService(Context.USER_SERVICE);
+            userManager = mUserManager = (UserManagerService) IUserManager.Stub.asInterface(b);
+        }
+        return userManager;
     }
 
     boolean startUser(final int userId, final boolean foreground) {
@@ -416,7 +433,7 @@
                 mService.mStackSupervisor.setLockTaskModeLocked(null,
                         ActivityManager.LOCK_TASK_MODE_NONE, "startUser", false);
 
-                final UserInfo userInfo = getUserManagerLocked().getUserInfo(userId);
+                final UserInfo userInfo = getUserInfo(userId);
                 if (userInfo == null) {
                     Slog.w(TAG, "No user info for user #" + userId);
                     return false;
@@ -507,8 +524,7 @@
                     intent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
                     mService.broadcastIntentLocked(null, null, intent,
                             null, null, 0, null, null, null, AppOpsManager.OP_NONE,
-                            null, false, false, ActivityManagerService.MY_PID, Process.SYSTEM_UID,
-                            userId);
+                            null, false, false, MY_PID, SYSTEM_UID, userId);
                 }
 
                 if ((userInfo.flags&UserInfo.FLAG_INITIALIZED) == 0) {
@@ -523,11 +539,10 @@
                                         onUserInitialized(uss, foreground, oldUserId, userId);
                                     }
                                 }, 0, null, null, null, AppOpsManager.OP_NONE,
-                                null, true, false, ActivityManagerService.MY_PID,
-                                Process.SYSTEM_UID, userId);
+                                null, true, false, MY_PID, SYSTEM_UID, userId);
                         uss.initializing = true;
                     } else {
-                        getUserManagerLocked().makeInitialized(userInfo.id);
+                        getUserManager().makeInitialized(userInfo.id);
                     }
                 }
 
@@ -551,9 +566,8 @@
                                         int sendingUser) throws RemoteException {
                                 }
                             }, 0, null, null,
-                            new String[]{INTERACT_ACROSS_USERS}, AppOpsManager.OP_NONE,
-                            null, true, false, ActivityManagerService.MY_PID, Process.SYSTEM_UID,
-                            UserHandle.USER_ALL);
+                            new String[] {INTERACT_ACROSS_USERS}, AppOpsManager.OP_NONE,
+                            null, true, false, MY_PID, SYSTEM_UID, UserHandle.USER_ALL);
                 }
             }
         } finally {
@@ -563,6 +577,22 @@
         return true;
     }
 
+    /**
+     * Start user, if its not already running, and bring it to foreground.
+     */
+    boolean startUserInForeground(final int userId, Dialog dlg) {
+        boolean result = startUser(userId, /* foreground */ true);
+        dlg.dismiss();
+        return result;
+    }
+
+    void showUserSwitchDialog(int userId, String userName) {
+        // The dialog will show and then initiate the user switch by calling startUserInForeground
+        Dialog d = new UserSwitchingDialog(mService, mService.mContext, userId, userName,
+                true /* above system */);
+        d.show();
+    }
+
     void dispatchForegroundProfileChanged(int userId) {
         final int observerCount = mUserSwitchObservers.beginBroadcast();
         for (int i = 0; i < observerCount; i++) {
@@ -657,7 +687,7 @@
         synchronized (mService) {
             if (clearInitializing) {
                 uss.initializing = false;
-                getUserManagerLocked().makeInitialized(uss.mHandle.getIdentifier());
+                getUserManager().makeInitialized(uss.mHandle.getIdentifier());
             }
             if (clearSwitching) {
                 uss.switching = false;
@@ -683,8 +713,143 @@
             mService.mStackSupervisor.resumeTopActivitiesLocked();
         }
         EventLogTags.writeAmSwitchUser(newUserId);
-        getUserManagerLocked().onUserForeground(newUserId);
-        mService.sendUserSwitchBroadcastsLocked(oldUserId, newUserId);
+        getUserManager().onUserForeground(newUserId);
+        sendUserSwitchBroadcastsLocked(oldUserId, newUserId);
+    }
+
+    void sendUserSwitchBroadcastsLocked(int oldUserId, int newUserId) {
+        long ident = Binder.clearCallingIdentity();
+        try {
+            Intent intent;
+            if (oldUserId >= 0) {
+                // Send USER_BACKGROUND broadcast to all profiles of the outgoing user
+                List<UserInfo> profiles = getUserManager().getProfiles(oldUserId, false);
+                int count = profiles.size();
+                for (int i = 0; i < count; i++) {
+                    int profileUserId = profiles.get(i).id;
+                    intent = new Intent(Intent.ACTION_USER_BACKGROUND);
+                    intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
+                            | Intent.FLAG_RECEIVER_FOREGROUND);
+                    intent.putExtra(Intent.EXTRA_USER_HANDLE, profileUserId);
+                    mService.broadcastIntentLocked(null, null, intent,
+                            null, null, 0, null, null, null, AppOpsManager.OP_NONE,
+                            null, false, false, MY_PID, SYSTEM_UID, profileUserId);
+                }
+            }
+            if (newUserId >= 0) {
+                // Send USER_FOREGROUND broadcast to all profiles of the incoming user
+                List<UserInfo> profiles = getUserManager().getProfiles(newUserId, false);
+                int count = profiles.size();
+                for (int i = 0; i < count; i++) {
+                    int profileUserId = profiles.get(i).id;
+                    intent = new Intent(Intent.ACTION_USER_FOREGROUND);
+                    intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
+                            | Intent.FLAG_RECEIVER_FOREGROUND);
+                    intent.putExtra(Intent.EXTRA_USER_HANDLE, profileUserId);
+                    mService.broadcastIntentLocked(null, null, intent,
+                            null, null, 0, null, null, null, AppOpsManager.OP_NONE,
+                            null, false, false, MY_PID, SYSTEM_UID, profileUserId);
+                }
+                intent = new Intent(Intent.ACTION_USER_SWITCHED);
+                intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
+                        | Intent.FLAG_RECEIVER_FOREGROUND);
+                intent.putExtra(Intent.EXTRA_USER_HANDLE, newUserId);
+                mService.broadcastIntentLocked(null, null, intent,
+                        null, null, 0, null, null,
+                        new String[] {android.Manifest.permission.MANAGE_USERS},
+                        AppOpsManager.OP_NONE, null, false, false, MY_PID, SYSTEM_UID,
+                        UserHandle.USER_ALL);
+            }
+        } finally {
+            Binder.restoreCallingIdentity(ident);
+        }
+    }
+
+
+    int handleIncomingUser(int callingPid, int callingUid, int userId, boolean allowAll,
+            int allowMode, String name, String callerPackage) {
+        final int callingUserId = UserHandle.getUserId(callingUid);
+        if (callingUserId == userId) {
+            return userId;
+        }
+
+        // Note that we may be accessing mCurrentUserId outside of a lock...
+        // shouldn't be a big deal, if this is being called outside
+        // of a locked context there is intrinsically a race with
+        // the value the caller will receive and someone else changing it.
+        // We assume that USER_CURRENT_OR_SELF will use the current user; later
+        // we will switch to the calling user if access to the current user fails.
+        int targetUserId = unsafeConvertIncomingUserLocked(userId);
+
+        if (callingUid != 0 && callingUid != SYSTEM_UID) {
+            final boolean allow;
+            if (mService.checkComponentPermission(INTERACT_ACROSS_USERS_FULL, callingPid,
+                    callingUid, -1, true) == PackageManager.PERMISSION_GRANTED) {
+                // If the caller has this permission, they always pass go.  And collect $200.
+                allow = true;
+            } else if (allowMode == ALLOW_FULL_ONLY) {
+                // We require full access, sucks to be you.
+                allow = false;
+            } else if (mService.checkComponentPermission(INTERACT_ACROSS_USERS, callingPid,
+                    callingUid, -1, true) != PackageManager.PERMISSION_GRANTED) {
+                // If the caller does not have either permission, they are always doomed.
+                allow = false;
+            } else if (allowMode == ALLOW_NON_FULL) {
+                // We are blanket allowing non-full access, you lucky caller!
+                allow = true;
+            } else if (allowMode == ALLOW_NON_FULL_IN_PROFILE) {
+                // We may or may not allow this depending on whether the two users are
+                // in the same profile.
+                allow = isSameProfileGroup(callingUserId, targetUserId);
+            } else {
+                throw new IllegalArgumentException("Unknown mode: " + allowMode);
+            }
+            if (!allow) {
+                if (userId == UserHandle.USER_CURRENT_OR_SELF) {
+                    // In this case, they would like to just execute as their
+                    // owner user instead of failing.
+                    targetUserId = callingUserId;
+                } else {
+                    StringBuilder builder = new StringBuilder(128);
+                    builder.append("Permission Denial: ");
+                    builder.append(name);
+                    if (callerPackage != null) {
+                        builder.append(" from ");
+                        builder.append(callerPackage);
+                    }
+                    builder.append(" asks to run as user ");
+                    builder.append(userId);
+                    builder.append(" but is calling from user ");
+                    builder.append(UserHandle.getUserId(callingUid));
+                    builder.append("; this requires ");
+                    builder.append(INTERACT_ACROSS_USERS_FULL);
+                    if (allowMode != ALLOW_FULL_ONLY) {
+                        builder.append(" or ");
+                        builder.append(INTERACT_ACROSS_USERS);
+                    }
+                    String msg = builder.toString();
+                    Slog.w(TAG, msg);
+                    throw new SecurityException(msg);
+                }
+            }
+        }
+        if (!allowAll && targetUserId < 0) {
+            throw new IllegalArgumentException(
+                    "Call does not support special user #" + targetUserId);
+        }
+        // Check shell permission
+        if (callingUid == Process.SHELL_UID && targetUserId >= UserHandle.USER_SYSTEM) {
+            if (hasUserRestriction(UserManager.DISALLOW_DEBUGGING_FEATURES, targetUserId)) {
+                throw new SecurityException("Shell does not have permission to access user "
+                        + targetUserId + "\n " + Debug.getCallers(3));
+            }
+        }
+        return targetUserId;
+    }
+
+    int unsafeConvertIncomingUserLocked(int userId) {
+        return (userId == UserHandle.USER_CURRENT || userId == UserHandle.USER_CURRENT_OR_SELF)
+                ? getCurrentUserIdLocked(): userId;
     }
 
     void registerUserSwitchObserver(IUserSwitchObserver observer) {
@@ -705,7 +870,7 @@
         mUserSwitchObservers.unregister(observer);
     }
 
-    UserState getStartedUserState(int userId) {
+    UserState getStartedUserStateLocked(int userId) {
         return mStartedUsers.get(userId);
     }
 
@@ -746,9 +911,8 @@
                 intent.addFlags(Intent.FLAG_RECEIVER_NO_ABORT);
                 mService.broadcastIntentLocked(null, null, intent, null,
                         resultTo, 0, null, null,
-                        new String[]{android.Manifest.permission.RECEIVE_BOOT_COMPLETED},
-                        AppOpsManager.OP_NONE, null, true, false,
-                        ActivityManagerService.MY_PID, Process.SYSTEM_UID, userId);
+                        new String[] {android.Manifest.permission.RECEIVE_BOOT_COMPLETED},
+                        AppOpsManager.OP_NONE, null, true, false, MY_PID, SYSTEM_UID, userId);
             }
         }
     }
@@ -759,7 +923,7 @@
      * background.
      */
     void updateCurrentProfileIdsLocked() {
-        final List<UserInfo> profiles = getUserManagerLocked().getProfiles(mCurrentUserId,
+        final List<UserInfo> profiles = getUserManager().getProfiles(mCurrentUserId,
                 false /* enabledOnly */);
         int[] currentProfileIds = new int[profiles.size()]; // profiles will not be null
         for (int i = 0; i < currentProfileIds.length; i++) {
@@ -769,7 +933,7 @@
 
         synchronized (mUserProfileGroupIdsSelfLocked) {
             mUserProfileGroupIdsSelfLocked.clear();
-            final List<UserInfo> users = getUserManagerLocked().getUsers(false);
+            final List<UserInfo> users = getUserManager().getUsers(false);
             for (int i = 0; i < users.size(); i++) {
                 UserInfo user = users.get(i);
                 if (user.profileGroupId != UserInfo.NO_PROFILE_GROUP_ID) {
@@ -783,6 +947,18 @@
         return mStartedUserArray;
     }
 
+    boolean isUserRunningLocked(int userId, boolean orStopped) {
+        UserState state = getStartedUserStateLocked(userId);
+        if (state == null) {
+            return false;
+        }
+        if (orStopped) {
+            return true;
+        }
+        return state.mState != UserState.STATE_STOPPING
+                && state.mState != UserState.STATE_SHUTDOWN;
+    }
+
     UserInfo getCurrentUser() {
         if ((mService.checkCallingPermission(INTERACT_ACROSS_USERS)
                 != PackageManager.PERMISSION_GRANTED) && (
@@ -802,11 +978,50 @@
 
     UserInfo getCurrentUserLocked() {
         int userId = mTargetUserId != UserHandle.USER_NULL ? mTargetUserId : mCurrentUserId;
-        return getUserManagerLocked().getUserInfo(userId);
+        return getUserInfo(userId);
+    }
+
+    int getCurrentOrTargetUserIdLocked() {
+        return mTargetUserId != UserHandle.USER_NULL ? mTargetUserId : mCurrentUserId;
     }
 
     int getCurrentUserIdLocked() {
-        return mTargetUserId != UserHandle.USER_NULL ? mTargetUserId : mCurrentUserId;
+        return mCurrentUserId;
+    }
+
+    int setTargetUserIdLocked(int targetUserId) {
+        return mTargetUserId = targetUserId;
+    }
+
+    int[] getUsers() {
+        UserManagerService ums = getUserManager();
+        return ums != null ? ums.getUserIds() : new int[] { 0 };
+    }
+
+    UserInfo getUserInfo(int userId) {
+        return getUserManager().getUserInfo(userId);
+    }
+
+    int[] getUserIds() {
+        return getUserManager().getUserIds();
+    }
+
+    boolean exists(int userId) {
+        return getUserManager().exists(userId);
+    }
+
+    boolean hasUserRestriction(String restriction, int userId) {
+        return getUserManager().hasUserRestriction(restriction, userId);
+    }
+
+    Set<Integer> getProfileIds(int userId) {
+        Set<Integer> userIds = new HashSet<>();
+        final List<UserInfo> profiles = getUserManager().getProfiles(userId,
+                false /* enabledOnly */);
+        for (UserInfo user : profiles) {
+            userIds.add(user.id);
+        }
+        return userIds;
     }
 
     boolean isSameProfileGroup(int callingUserId, int targetUserId) {
@@ -824,6 +1039,10 @@
         return ArrayUtils.contains(mCurrentProfileIds, userId);
     }
 
+    int[] getCurrentProfileIdsLocked() {
+        return mCurrentProfileIds;
+    }
+
     void dump(PrintWriter pw, boolean dumpAll) {
         pw.println("  mStartedUsers:");
         for (int i = 0; i < mStartedUsers.size(); i++) {
@@ -858,5 +1077,4 @@
             }
         }
     }
-
 }
diff --git a/services/core/java/com/android/server/am/UserSwitchingDialog.java b/services/core/java/com/android/server/am/UserSwitchingDialog.java
index 5a66f4a..28b4096 100644
--- a/services/core/java/com/android/server/am/UserSwitchingDialog.java
+++ b/services/core/java/com/android/server/am/UserSwitchingDialog.java
@@ -97,7 +97,7 @@
     void startUser() {
         synchronized (this) {
             if (!mStartedUser) {
-                mService.startUserInForeground(mUserId, this);
+                mService.mUserController.startUserInForeground(mUserId, this);
                 mStartedUser = true;
                 final View decorView = getWindow().getDecorView();
                 if (decorView != null) {
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 4863603..c497ad4 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -16553,7 +16553,7 @@
      */
     private void removeUnusedPackagesLILPw(UserManagerService userManager, final int userHandle) {
         final boolean DEBUG_CLEAN_APKS = false;
-        int [] users = userManager.getUserIdsLPr();
+        int [] users = userManager.getUserIds();
         Iterator<PackageSetting> psit = mSettings.mPackages.values().iterator();
         while (psit.hasNext()) {
             PackageSetting ps = psit.next();
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 925acb8..c41d493 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -95,13 +95,15 @@
  * Service for {@link UserManager}.
  *
  * Method naming convention:
- * - Methods suffixed with "Locked" should be called within the {@code this} lock.
- * - Methods suffixed with "RL" should be called within the {@link #mRestrictionsLock} lock.
+ * <ul>
+ * <li> Methods suffixed with "LILP" should be called within {@link #mInstallLock} and
+ * {@link #mPackagesLock} locks obtained in the respective order.
+ * <li> Methods suffixed with "LR" should be called within the {@link #mRestrictionsLock} lock.
+ * <li> Methods suffixed with "LU" should be called within the {@link #mUsersLock} lock.
+ * </ul>
  */
 public class UserManagerService extends IUserManager.Stub {
-
     private static final String LOG_TAG = "UserManagerService";
-
     private static final boolean DBG = false; // DO NOT SUBMIT WITH TRUE
 
     private static final String TAG_NAME = "name";
@@ -163,15 +165,17 @@
     private final PackageManagerService mPm;
     private final Object mInstallLock;
     private final Object mPackagesLock;
+    // Short-term lock for internal state, when interaction/sync with PM is not required
+    private final Object mUsersLock = new Object();
+    private final Object mRestrictionsLock = new Object();
 
     private final Handler mHandler;
 
     private final File mUsersDir;
     private final File mUserListFile;
 
-    private final SparseArray<UserInfo> mUsers = new SparseArray<UserInfo>();
-
-    private final Object mRestrictionsLock = new Object();
+    @GuardedBy("mUsersLock")
+    private final SparseArray<UserInfo> mUsers = new SparseArray<>();
 
     /**
      * User restrictions set via UserManager.  This doesn't include restrictions set by
@@ -182,7 +186,7 @@
      * maybe shared between {@link #mBaseUserRestrictions} and
      * {@link #mCachedEffectiveUserRestrictions}, but they should always updated separately.
      * (Otherwise we won't be able to detect what restrictions have changed in
-     * {@link #updateUserRestrictionsInternalRL).
+     * {@link #updateUserRestrictionsInternalLR}.
      */
     @GuardedBy("mRestrictionsLock")
     private final SparseArray<Bundle> mBaseUserRestrictions = new SparseArray<>();
@@ -197,15 +201,15 @@
      * maybe shared between {@link #mBaseUserRestrictions} and
      * {@link #mCachedEffectiveUserRestrictions}, but they should always updated separately.
      * (Otherwise we won't be able to detect what restrictions have changed in
-     * {@link #updateUserRestrictionsInternalRL).
+     * {@link #updateUserRestrictionsInternalLR}.
      */
     @GuardedBy("mRestrictionsLock")
     private final SparseArray<Bundle> mCachedEffectiveUserRestrictions = new SparseArray<>();
 
     /**
-     * User restrictions that have already been applied in {@link #applyUserRestrictionsRL}.  We
+     * User restrictions that have already been applied in {@link #applyUserRestrictionsLR}.  We
      * use it to detect restrictions that have changed since the last
-     * {@link #applyUserRestrictionsRL} call.
+     * {@link #applyUserRestrictionsLR} call.
      */
     @GuardedBy("mRestrictionsLock")
     private final SparseArray<Bundle> mAppliedUserRestrictions = new SparseArray<>();
@@ -216,9 +220,10 @@
      * Set of user IDs being actively removed. Removed IDs linger in this set
      * for several seconds to work around a VFS caching issue.
      */
-    // @GuardedBy("mPackagesLock")
+    @GuardedBy("mUsersLock")
     private final SparseBooleanArray mRemovingUserIds = new SparseBooleanArray();
 
+    @GuardedBy("mUsersLock")
     private int[] mUserIds;
     private int mNextSerialNumber;
     private int mUserVersion = 0;
@@ -278,7 +283,7 @@
                         -1, -1);
                 mUserListFile = new File(mUsersDir, USER_LIST_FILENAME);
                 initDefaultGuestRestrictions();
-                readUserListLocked();
+                readUserListLILP();
                 sInstance = this;
             }
         }
@@ -289,21 +294,23 @@
     void systemReady() {
         synchronized (mInstallLock) {
             synchronized (mPackagesLock) {
-                // Prune out any partially created/partially removed users.
-                ArrayList<UserInfo> partials = new ArrayList<UserInfo>();
-                final int userSize = mUsers.size();
-                for (int i = 0; i < userSize; i++) {
-                    UserInfo ui = mUsers.valueAt(i);
-                    if ((ui.partial || ui.guestToRemove) && i != 0) {
-                        partials.add(ui);
+                synchronized (mUsersLock) {
+                    // Prune out any partially created/partially removed users.
+                    ArrayList<UserInfo> partials = new ArrayList<UserInfo>();
+                    final int userSize = mUsers.size();
+                    for (int i = 0; i < userSize; i++) {
+                        UserInfo ui = mUsers.valueAt(i);
+                        if ((ui.partial || ui.guestToRemove) && i != 0) {
+                            partials.add(ui);
+                        }
                     }
-                }
-                final int partialsSize = partials.size();
-                for (int i = 0; i < partialsSize; i++) {
-                    UserInfo ui = partials.get(i);
-                    Slog.w(LOG_TAG, "Removing partially created user " + ui.id
-                            + " (name=" + ui.name + ")");
-                    removeUserStateLocked(ui.id);
+                    final int partialsSize = partials.size();
+                    for (int i = 0; i < partialsSize; i++) {
+                        UserInfo ui = partials.get(i);
+                        Slog.w(LOG_TAG, "Removing partially created user " + ui.id
+                                + " (name=" + ui.name + ")");
+                        removeUserStateLILP(ui.id);
+                    }
                 }
             }
         }
@@ -323,7 +330,7 @@
     @Override
     public UserInfo getPrimaryUser() {
         checkManageUsersPermission("query users");
-        synchronized (mPackagesLock) {
+        synchronized (mUsersLock) {
             final int userSize = mUsers.size();
             for (int i = 0; i < userSize; i++) {
                 UserInfo ui = mUsers.valueAt(i);
@@ -338,7 +345,7 @@
     @Override
     public @NonNull List<UserInfo> getUsers(boolean excludeDying) {
         checkManageUsersPermission("query users");
-        synchronized (mPackagesLock) {
+        synchronized (mUsersLock) {
             ArrayList<UserInfo> users = new ArrayList<UserInfo>(mUsers.size());
             final int userSize = mUsers.size();
             for (int i = 0; i < userSize; i++) {
@@ -361,8 +368,8 @@
         }
         final long ident = Binder.clearCallingIdentity();
         try {
-            synchronized (mPackagesLock) {
-                return getProfilesLocked(userId, enabledOnly);
+            synchronized (mUsersLock) {
+                return getProfilesLU(userId, enabledOnly);
             }
         } finally {
             Binder.restoreCallingIdentity(ident);
@@ -370,8 +377,8 @@
     }
 
     /** Assume permissions already checked and caller's identity cleared */
-    private List<UserInfo> getProfilesLocked(int userId, boolean enabledOnly) {
-        UserInfo user = getUserInfoLocked(userId);
+    private List<UserInfo> getProfilesLU(int userId, boolean enabledOnly) {
+        UserInfo user = getUserInfoLU(userId);
         ArrayList<UserInfo> users = new ArrayList<UserInfo>(mUsers.size());
         if (user == null) {
             // Probably a dying user
@@ -398,8 +405,8 @@
     public int getCredentialOwnerProfile(int userHandle) {
         checkManageUsersPermission("get the credential owner");
         if (!"file".equals(SystemProperties.get("ro.crypto.type", "none"))) {
-            synchronized (mPackagesLock) {
-                UserInfo profileParent = getProfileParentLocked(userHandle);
+            synchronized (mUsersLock) {
+                UserInfo profileParent = getProfileParentLU(userHandle);
                 if (profileParent != null) {
                     return profileParent.id;
                 }
@@ -414,32 +421,35 @@
         if (userId == otherUserId) return true;
         checkManageUsersPermission("check if in the same profile group");
         synchronized (mPackagesLock) {
-            return isSameProfileGroupLocked(userId, otherUserId);
+            return isSameProfileGroupLP(userId, otherUserId);
         }
     }
 
-    private boolean isSameProfileGroupLocked(int userId, int otherUserId) {
-        UserInfo userInfo = getUserInfoLocked(userId);
-        if (userInfo == null || userInfo.profileGroupId == UserInfo.NO_PROFILE_GROUP_ID) {
-            return false;
+    private boolean isSameProfileGroupLP(int userId, int otherUserId) {
+        synchronized (mUsersLock) {
+            UserInfo userInfo = getUserInfoLU(userId);
+            if (userInfo == null || userInfo.profileGroupId == UserInfo.NO_PROFILE_GROUP_ID) {
+                return false;
+            }
+            UserInfo otherUserInfo = getUserInfoLU(otherUserId);
+            if (otherUserInfo == null
+                    || otherUserInfo.profileGroupId == UserInfo.NO_PROFILE_GROUP_ID) {
+                return false;
+            }
+            return userInfo.profileGroupId == otherUserInfo.profileGroupId;
         }
-        UserInfo otherUserInfo = getUserInfoLocked(otherUserId);
-        if (otherUserInfo == null || otherUserInfo.profileGroupId == UserInfo.NO_PROFILE_GROUP_ID) {
-            return false;
-        }
-        return userInfo.profileGroupId == otherUserInfo.profileGroupId;
     }
 
     @Override
     public UserInfo getProfileParent(int userHandle) {
         checkManageUsersPermission("get the profile parent");
-        synchronized (mPackagesLock) {
-            return getProfileParentLocked(userHandle);
+        synchronized (mUsersLock) {
+            return getProfileParentLU(userHandle);
         }
     }
 
-    private UserInfo getProfileParentLocked(int userHandle) {
-        UserInfo profile = getUserInfoLocked(userHandle);
+    private UserInfo getProfileParentLU(int userHandle) {
+        UserInfo profile = getUserInfoLU(userHandle);
         if (profile == null) {
             return null;
         }
@@ -447,11 +457,11 @@
         if (parentUserId == UserInfo.NO_PROFILE_GROUP_ID) {
             return null;
         } else {
-            return getUserInfoLocked(parentUserId);
+            return getUserInfoLU(parentUserId);
         }
     }
 
-    private boolean isProfileOf(UserInfo user, UserInfo profile) {
+    private static boolean isProfileOf(UserInfo user, UserInfo profile) {
         return user.id == profile.id ||
                 (user.profileGroupId != UserInfo.NO_PROFILE_GROUP_ID
                 && user.profileGroupId == profile.profileGroupId);
@@ -461,10 +471,13 @@
     public void setUserEnabled(int userId) {
         checkManageUsersPermission("enable user");
         synchronized (mPackagesLock) {
-            UserInfo info = getUserInfoLocked(userId);
+            UserInfo info;
+            synchronized (mUsersLock) {
+                info = getUserInfoLU(userId);
+            }
             if (info != null && !info.isEnabled()) {
                 info.flags ^= UserInfo.FLAG_DISABLED;
-                writeUserLocked(info);
+                writeUserLP(info);
             }
         }
     }
@@ -472,23 +485,23 @@
     @Override
     public UserInfo getUserInfo(int userId) {
         checkManageUsersPermission("query user");
-        synchronized (mPackagesLock) {
-            return getUserInfoLocked(userId);
+        synchronized (mUsersLock) {
+            return getUserInfoLU(userId);
         }
     }
 
     @Override
     public boolean isRestricted() {
-        synchronized (mPackagesLock) {
-            return getUserInfoLocked(UserHandle.getCallingUserId()).isRestricted();
+        synchronized (mUsersLock) {
+            return getUserInfoLU(UserHandle.getCallingUserId()).isRestricted();
         }
     }
 
     @Override
     public boolean canHaveRestrictedProfile(int userId) {
         checkManageUsersPermission("canHaveRestrictedProfile");
-        synchronized (mPackagesLock) {
-            final UserInfo userInfo = getUserInfoLocked(userId);
+        synchronized (mUsersLock) {
+            final UserInfo userInfo = getUserInfoLU(userId);
             if (userInfo == null || !userInfo.canHaveProfile()) {
                 return false;
             }
@@ -505,7 +518,7 @@
     /*
      * Should be locked on mUsers before calling this.
      */
-    private UserInfo getUserInfoLocked(int userId) {
+    private UserInfo getUserInfoLU(int userId) {
         UserInfo ui = mUsers.get(userId);
         // If it is partial and not in the process of being removed, return as unknown user.
         if (ui != null && ui.partial && !mRemovingUserIds.get(userId)) {
@@ -515,11 +528,19 @@
         return ui;
     }
 
+    /**
+     * Obtains {@link #mUsersLock} and return UserInfo from mUsers.
+     * <p>No permissions checking or any addition checks are made</p>
+     */
+    private UserInfo getUserInfoNoChecks(int userId) {
+        synchronized (mUsersLock) {
+            return mUsers.get(userId);
+        }
+    }
+
     /** Called by PackageManagerService */
     public boolean exists(int userId) {
-        synchronized (mPackagesLock) {
-            return mUsers.get(userId) != null;
-        }
+        return getUserInfoNoChecks(userId) != null;
     }
 
     @Override
@@ -527,14 +548,14 @@
         checkManageUsersPermission("rename users");
         boolean changed = false;
         synchronized (mPackagesLock) {
-            UserInfo info = mUsers.get(userId);
+            UserInfo info = getUserInfoNoChecks(userId);
             if (info == null || info.partial) {
                 Slog.w(LOG_TAG, "setUserName: unknown user #" + userId);
                 return;
             }
             if (name != null && !name.equals(info.name)) {
                 info.name = name;
-                writeUserLocked(info);
+                writeUserLP(info);
                 changed = true;
             }
         }
@@ -549,13 +570,13 @@
         long ident = Binder.clearCallingIdentity();
         try {
             synchronized (mPackagesLock) {
-                UserInfo info = mUsers.get(userId);
+                UserInfo info = getUserInfoNoChecks(userId);
                 if (info == null || info.partial) {
                     Slog.w(LOG_TAG, "setUserIcon: unknown user #" + userId);
                     return;
                 }
-                writeBitmapLocked(info, bitmap);
-                writeUserLocked(info);
+                writeBitmapLP(info, bitmap);
+                writeUserLP(info);
             }
             sendUserInfoChangedBroadcast(userId);
         } finally {
@@ -574,12 +595,12 @@
     public ParcelFileDescriptor getUserIcon(int userId) {
         String iconPath;
         synchronized (mPackagesLock) {
-            UserInfo info = mUsers.get(userId);
+            UserInfo info = getUserInfoNoChecks(userId);
             if (info == null || info.partial) {
                 Slog.w(LOG_TAG, "getUserIcon: unknown user #" + userId);
                 return null;
             }
-            int callingGroupId = mUsers.get(UserHandle.getCallingUserId()).profileGroupId;
+            int callingGroupId = getUserInfoNoChecks(UserHandle.getCallingUserId()).profileGroupId;
             if (callingGroupId == UserInfo.NO_PROFILE_GROUP_ID
                     || callingGroupId != info.profileGroupId) {
                 checkManageUsersPermission("get the icon of a user who is not related");
@@ -602,13 +623,14 @@
     public void makeInitialized(int userId) {
         checkManageUsersPermission("makeInitialized");
         synchronized (mPackagesLock) {
-            UserInfo info = mUsers.get(userId);
+            UserInfo info = getUserInfoNoChecks(userId);
             if (info == null || info.partial) {
                 Slog.w(LOG_TAG, "makeInitialized: unknown user #" + userId);
+                // TODO Check if we should return here instead of a null check below
             }
-            if ((info.flags&UserInfo.FLAG_INITIALIZED) == 0) {
+            if (info != null && (info.flags&UserInfo.FLAG_INITIALIZED) == 0) {
                 info.flags |= UserInfo.FLAG_INITIALIZED;
-                scheduleWriteUserLocked(info);
+                scheduleWriteUserLP(info);
             }
         }
     }
@@ -627,6 +649,7 @@
     @Override
     public Bundle getDefaultGuestRestrictions() {
         checkManageUsersPermission("getDefaultGuestRestrictions");
+        // TODO Switch to mGuestRestrictions for locking
         synchronized (mPackagesLock) {
             return new Bundle(mGuestRestrictions);
         }
@@ -635,15 +658,17 @@
     @Override
     public void setDefaultGuestRestrictions(Bundle restrictions) {
         checkManageUsersPermission("setDefaultGuestRestrictions");
-        synchronized (mPackagesLock) {
-            mGuestRestrictions.clear();
-            mGuestRestrictions.putAll(restrictions);
-            writeUserListLocked();
+        synchronized (mInstallLock) {
+            synchronized (mPackagesLock) {
+                mGuestRestrictions.clear();
+                mGuestRestrictions.putAll(restrictions);
+                writeUserListLILP();
+            }
         }
     }
 
     @GuardedBy("mRestrictionsLock")
-    private Bundle computeEffectiveUserRestrictionsRL(int userId) {
+    private Bundle computeEffectiveUserRestrictionsLR(int userId) {
         final DevicePolicyManagerInternal dpmi =
                 LocalServices.getService(DevicePolicyManagerInternal.class);
         final Bundle systemRestrictions = mBaseUserRestrictions.get(userId);
@@ -659,7 +684,7 @@
     }
 
     @GuardedBy("mRestrictionsLock")
-    private void invalidateEffectiveUserRestrictionsRL(int userId) {
+    private void invalidateEffectiveUserRestrictionsLR(int userId) {
         if (DBG) {
             Log.d(LOG_TAG, "invalidateEffectiveUserRestrictions userId=" + userId);
         }
@@ -670,7 +695,7 @@
         synchronized (mRestrictionsLock) {
             Bundle restrictions = mCachedEffectiveUserRestrictions.get(userId);
             if (restrictions == null) {
-                restrictions = computeEffectiveUserRestrictionsRL(userId);
+                restrictions = computeEffectiveUserRestrictionsLR(userId);
                 mCachedEffectiveUserRestrictions.put(userId, restrictions);
             }
             return restrictions;
@@ -716,7 +741,7 @@
             UserRestrictionsUtils.merge(newRestrictions, mBaseUserRestrictions.get(userId));
             newRestrictions.putBoolean(key, value);
 
-            updateUserRestrictionsInternalRL(newRestrictions, userId);
+            updateUserRestrictionsInternalLR(newRestrictions, userId);
         }
     }
 
@@ -732,7 +757,7 @@
      * @param userId target user ID.
      */
     @GuardedBy("mRestrictionsLock")
-    private void updateUserRestrictionsInternalRL(
+    private void updateUserRestrictionsInternalLR(
             @Nullable Bundle newRestrictions, int userId) {
         if (DBG) {
             Log.d(LOG_TAG, "updateUserRestrictionsInternalLocked userId=" + userId
@@ -747,15 +772,15 @@
             mBaseUserRestrictions.put(userId, newRestrictions);
         }
 
-        final Bundle effective = computeEffectiveUserRestrictionsRL(userId);
+        final Bundle effective = computeEffectiveUserRestrictionsLR(userId);
 
         mCachedEffectiveUserRestrictions.put(userId, effective);
 
-        applyUserRestrictionsRL(userId, effective);
+        applyUserRestrictionsLR(userId, effective);
     }
 
     @GuardedBy("mRestrictionsLock")
-    private void applyUserRestrictionsRL(int userId, Bundle newRestrictions) {
+    private void applyUserRestrictionsLR(int userId, Bundle newRestrictions) {
         final Bundle prevRestrictions = mAppliedUserRestrictions.get(userId);
 
         if (DBG) {
@@ -779,12 +804,12 @@
     }
 
     @GuardedBy("mRestrictionsLock")
-    private void updateEffectiveUserRestrictionsRL(int userId) {
-        updateUserRestrictionsInternalRL(null, userId);
+    private void updateEffectiveUserRestrictionsLR(int userId) {
+        updateUserRestrictionsInternalLR(null, userId);
     }
 
     @GuardedBy("mRestrictionsLock")
-    private void updateEffectiveUserRestrictionsForAllUsersRL() {
+    private void updateEffectiveUserRestrictionsForAllUsersLR() {
         // First, invalidate all cached values.
         mCachedEffectiveUserRestrictions.clear();
 
@@ -808,7 +833,7 @@
                 // TODO: "Apply restrictions upon user start hasn't been implemented.  Implement it.
                 synchronized (mRestrictionsLock) {
                     for (int i = 0; i < runningUsers.length; i++) {
-                        updateUserRestrictionsInternalRL(null, runningUsers[i]);
+                        updateUserRestrictionsInternalLR(null, runningUsers[i]);
                     }
                 }
             }
@@ -819,8 +844,12 @@
     /**
      * Check if we've hit the limit of how many users can be created.
      */
-    private boolean isUserLimitReachedLocked() {
-        return getAliveUsersExcludingGuestsCountLocked() >= UserManager.getMaxSupportedUsers();
+    private boolean isUserLimitReached() {
+        int count;
+        synchronized (mUsersLock) {
+            count = getAliveUsersExcludingGuestsCountLU();
+        }
+        return count >= UserManager.getMaxSupportedUsers();
     }
 
     @Override
@@ -838,18 +867,18 @@
         if (managedProfilesCount >= MAX_MANAGED_PROFILES) {
             return false;
         }
-        synchronized(mPackagesLock) {
-            UserInfo userInfo = getUserInfoLocked(userId);
+        synchronized(mUsersLock) {
+            UserInfo userInfo = getUserInfoLU(userId);
             if (!userInfo.canHaveProfile()) {
                 return false;
             }
-            int usersCount = getAliveUsersExcludingGuestsCountLocked();
+            int usersCount = getAliveUsersExcludingGuestsCountLU();
             // We allow creating a managed profile in the special case where there is only one user.
             return usersCount == 1 || usersCount < UserManager.getMaxSupportedUsers();
         }
     }
 
-    private int getAliveUsersExcludingGuestsCountLocked() {
+    private int getAliveUsersExcludingGuestsCountLU() {
         int aliveUserCount = 0;
         final int totalUserCount = mUsers.size();
         // Skip over users being removed
@@ -888,7 +917,7 @@
         }
     }
 
-    private void writeBitmapLocked(UserInfo info, Bitmap bitmap) {
+    private void writeBitmapLP(UserInfo info, Bitmap bitmap) {
         try {
             File dir = new File(mUsersDir, Integer.toString(info.id));
             File file = new File(dir, USER_PHOTO_FILENAME);
@@ -922,18 +951,14 @@
      * @return the array of user ids.
      */
     public int[] getUserIds() {
-        synchronized (mPackagesLock) {
+        synchronized (mUsersLock) {
             return mUserIds;
         }
     }
 
-    int[] getUserIdsLPr() {
-        return mUserIds;
-    }
-
-    private void readUserListLocked() {
+    private void readUserListLILP() {
         if (!mUserListFile.exists()) {
-            fallbackToSingleUserLocked();
+            fallbackToSingleUserLILP();
             return;
         }
         FileInputStream fis = null;
@@ -950,7 +975,7 @@
 
             if (type != XmlPullParser.START_TAG) {
                 Slog.e(LOG_TAG, "Unable to read user list");
-                fallbackToSingleUserLocked();
+                fallbackToSingleUserLILP();
                 return;
             }
 
@@ -971,12 +996,14 @@
                     final String name = parser.getName();
                     if (name.equals(TAG_USER)) {
                         String id = parser.getAttributeValue(null, ATTR_ID);
-                        UserInfo user = readUserLocked(Integer.parseInt(id));
+                        UserInfo user = readUserLILP(Integer.parseInt(id));
 
                         if (user != null) {
-                            mUsers.put(user.id, user);
-                            if (mNextSerialNumber < 0 || mNextSerialNumber <= user.id) {
-                                mNextSerialNumber = user.id + 1;
+                            synchronized (mUsersLock) {
+                                mUsers.put(user.id, user);
+                                if (mNextSerialNumber < 0 || mNextSerialNumber <= user.id) {
+                                    mNextSerialNumber = user.id + 1;
+                                }
                             }
                         }
                     } else if (name.equals(TAG_GUEST_RESTRICTIONS)) {
@@ -993,12 +1020,12 @@
                     }
                 }
             }
-            updateUserIdsLocked();
-            upgradeIfNecessaryLocked();
+            updateUserIds();
+            upgradeIfNecessaryLILP();
         } catch (IOException ioe) {
-            fallbackToSingleUserLocked();
+            fallbackToSingleUserLILP();
         } catch (XmlPullParserException pe) {
-            fallbackToSingleUserLocked();
+            fallbackToSingleUserLILP();
         } finally {
             if (fis != null) {
                 try {
@@ -1012,24 +1039,24 @@
     /**
      * Upgrade steps between versions, either for fixing bugs or changing the data format.
      */
-    private void upgradeIfNecessaryLocked() {
+    private void upgradeIfNecessaryLILP() {
         int userVersion = mUserVersion;
         if (userVersion < 1) {
             // Assign a proper name for the owner, if not initialized correctly before
-            UserInfo user = mUsers.get(UserHandle.USER_SYSTEM);
+            UserInfo user = getUserInfoNoChecks(UserHandle.USER_SYSTEM);
             if ("Primary".equals(user.name)) {
                 user.name = mContext.getResources().getString(com.android.internal.R.string.owner_name);
-                scheduleWriteUserLocked(user);
+                scheduleWriteUserLP(user);
             }
             userVersion = 1;
         }
 
         if (userVersion < 2) {
             // Owner should be marked as initialized
-            UserInfo user = mUsers.get(UserHandle.USER_SYSTEM);
+            UserInfo user = getUserInfoNoChecks(UserHandle.USER_SYSTEM);
             if ((user.flags & UserInfo.FLAG_INITIALIZED) == 0) {
                 user.flags |= UserInfo.FLAG_INITIALIZED;
-                scheduleWriteUserLocked(user);
+                scheduleWriteUserLP(user);
             }
             userVersion = 2;
         }
@@ -1046,13 +1073,15 @@
 
         if (userVersion < 6) {
             final boolean splitSystemUser = UserManager.isSplitSystemUser();
-            for (int i = 0; i < mUsers.size(); i++) {
-                UserInfo user = mUsers.valueAt(i);
-                // In non-split mode, only user 0 can have restricted profiles
-                if (!splitSystemUser && user.isRestricted()
-                        && (user.restrictedProfileParentId == UserInfo.NO_PROFILE_GROUP_ID)) {
-                    user.restrictedProfileParentId = UserHandle.USER_SYSTEM;
-                    scheduleWriteUserLocked(user);
+            synchronized (mUsersLock) {
+                for (int i = 0; i < mUsers.size(); i++) {
+                    UserInfo user = mUsers.valueAt(i);
+                    // In non-split mode, only user 0 can have restricted profiles
+                    if (!splitSystemUser && user.isRestricted()
+                            && (user.restrictedProfileParentId == UserInfo.NO_PROFILE_GROUP_ID)) {
+                        user.restrictedProfileParentId = UserHandle.USER_SYSTEM;
+                        scheduleWriteUserLP(user);
+                    }
                 }
             }
             userVersion = 6;
@@ -1063,11 +1092,11 @@
                     + USER_VERSION);
         } else {
             mUserVersion = userVersion;
-            writeUserListLocked();
+            writeUserListLILP();
         }
     }
 
-    private void fallbackToSingleUserLocked() {
+    private void fallbackToSingleUserLILP() {
         int flags = UserInfo.FLAG_INITIALIZED;
         // In split system user mode, the admin and primary flags are assigned to the first human
         // user.
@@ -1078,7 +1107,9 @@
         UserInfo system = new UserInfo(UserHandle.USER_SYSTEM,
                 mContext.getResources().getString(com.android.internal.R.string.owner_name), null,
                 flags);
-        mUsers.put(system.id, system);
+        synchronized (mUsersLock) {
+            mUsers.put(system.id, system);
+        }
         mNextSerialNumber = MIN_USER_ID;
         mUserVersion = USER_VERSION;
 
@@ -1087,14 +1118,14 @@
             mBaseUserRestrictions.append(UserHandle.USER_SYSTEM, restrictions);
         }
 
-        updateUserIdsLocked();
+        updateUserIds();
         initDefaultGuestRestrictions();
 
-        writeUserListLocked();
-        writeUserLocked(system);
+        writeUserListLILP();
+        writeUserLP(system);
     }
 
-    private void scheduleWriteUserLocked(UserInfo userInfo) {
+    private void scheduleWriteUserLP(UserInfo userInfo) {
         if (!mHandler.hasMessages(WRITE_USER_MSG, userInfo)) {
             Message msg = mHandler.obtainMessage(WRITE_USER_MSG, userInfo);
             mHandler.sendMessageDelayed(msg, WRITE_USER_DELAY);
@@ -1108,7 +1139,7 @@
      *   <name>Primary</name>
      * </user>
      */
-    private void writeUserLocked(UserInfo userInfo) {
+    private void writeUserLP(UserInfo userInfo) {
         FileOutputStream fos = null;
         AtomicFile userFile = new AtomicFile(new File(mUsersDir, userInfo.id + XML_SUFFIX));
         try {
@@ -1174,7 +1205,8 @@
      *   <user id="2"></user>
      * </users>
      */
-    private void writeUserListLocked() {
+    private void writeUserListLILP() {
+        // TODO Investigate removing a dependency on mInstallLock
         FileOutputStream fos = null;
         AtomicFile userListFile = new AtomicFile(mUserListFile);
         try {
@@ -1195,11 +1227,17 @@
             UserRestrictionsUtils
                     .writeRestrictions(serializer, mGuestRestrictions, TAG_RESTRICTIONS);
             serializer.endTag(null, TAG_GUEST_RESTRICTIONS);
-            final int userSize = mUsers.size();
-            for (int i = 0; i < userSize; i++) {
-                UserInfo user = mUsers.valueAt(i);
+            int[] userIdsToWrite;
+            synchronized (mUsersLock) {
+                userIdsToWrite = new int[mUsers.size()];
+                for (int i = 0; i < userIdsToWrite.length; i++) {
+                    UserInfo user = mUsers.valueAt(i);
+                    userIdsToWrite[i] = user.id;
+                }
+            }
+            for (int id : userIdsToWrite) {
                 serializer.startTag(null, TAG_USER);
-                serializer.attribute(null, ATTR_ID, Integer.toString(user.id));
+                serializer.attribute(null, ATTR_ID, Integer.toString(id));
                 serializer.endTag(null, TAG_USER);
             }
 
@@ -1213,7 +1251,7 @@
         }
     }
 
-    private UserInfo readUserLocked(int id) {
+    private UserInfo readUserLILP(int id) {
         int flags = 0;
         int serialNumber = id;
         String name = null;
@@ -1407,20 +1445,22 @@
                 synchronized (mPackagesLock) {
                     UserInfo parent = null;
                     if (parentId != UserHandle.USER_NULL) {
-                        parent = getUserInfoLocked(parentId);
+                        synchronized (mUsersLock) {
+                            parent = getUserInfoLU(parentId);
+                        }
                         if (parent == null) return null;
                     }
                     if (isManagedProfile && !canAddMoreManagedProfiles(parentId)) {
                         Log.e(LOG_TAG, "Cannot add more managed profiles for user " + parentId);
                         return null;
                     }
-                    if (!isGuest && !isManagedProfile && isUserLimitReachedLocked()) {
+                    if (!isGuest && !isManagedProfile && isUserLimitReached()) {
                         // If we're not adding a guest user or a managed profile and the limit has
                         // been reached, cannot add a user.
                         return null;
                     }
                     // If we're adding a guest and there already exists one, bail.
-                    if (isGuest && findCurrentGuestUserLocked() != null) {
+                    if (isGuest && findCurrentGuestUser() != null) {
                         return null;
                     }
                     // In legacy mode, restricted profile's parent can only be the owner user
@@ -1454,7 +1494,7 @@
                             flags |= UserInfo.FLAG_ADMIN;
                         }
                     }
-                    userId = getNextAvailableIdLocked();
+                    userId = getNextAvailableId();
                     userInfo = new UserInfo(userId, name, null, flags);
                     userInfo.serialNumber = mNextSerialNumber++;
                     long now = System.currentTimeMillis();
@@ -1462,12 +1502,12 @@
                     userInfo.partial = true;
                     Environment.getUserSystemDirectory(userInfo.id).mkdirs();
                     mUsers.put(userId, userInfo);
-                    writeUserListLocked();
+                    writeUserListLILP();
                     if (parent != null) {
                         if (isManagedProfile) {
                             if (parent.profileGroupId == UserInfo.NO_PROFILE_GROUP_ID) {
                                 parent.profileGroupId = parent.id;
-                                scheduleWriteUserLocked(parent);
+                                scheduleWriteUserLP(parent);
                             }
                             userInfo.profileGroupId = parent.profileGroupId;
                         } else if (isRestricted) {
@@ -1476,7 +1516,7 @@
                             }
                             if (parent.restrictedProfileParentId == UserInfo.NO_PROFILE_GROUP_ID) {
                                 parent.restrictedProfileParentId = parent.id;
-                                scheduleWriteUserLocked(parent);
+                                scheduleWriteUserLP(parent);
                             }
                             userInfo.restrictedProfileParentId = parent.restrictedProfileParentId;
                         }
@@ -1495,8 +1535,8 @@
                     }
                     mPm.createNewUserLILPw(userId);
                     userInfo.partial = false;
-                    scheduleWriteUserLocked(userInfo);
-                    updateUserIdsLocked();
+                    scheduleWriteUserLP(userInfo);
+                    updateUserIds();
                     Bundle restrictions = new Bundle();
                     synchronized (mRestrictionsLock) {
                         mBaseUserRestrictions.append(userId, restrictions);
@@ -1539,12 +1579,14 @@
      * Find the current guest user. If the Guest user is partial,
      * then do not include it in the results as it is about to die.
      */
-    private UserInfo findCurrentGuestUserLocked() {
-        final int size = mUsers.size();
-        for (int i = 0; i < size; i++) {
-            final UserInfo user = mUsers.valueAt(i);
-            if (user.isGuest() && !user.guestToRemove && !mRemovingUserIds.get(user.id)) {
-                return user;
+    private UserInfo findCurrentGuestUser() {
+        synchronized (mUsersLock) {
+            final int size = mUsers.size();
+            for (int i = 0; i < size; i++) {
+                final UserInfo user = mUsers.valueAt(i);
+                if (user.isGuest() && !user.guestToRemove && !mRemovingUserIds.get(user.id)) {
+                    return user;
+                }
             }
         }
         return null;
@@ -1568,9 +1610,11 @@
         try {
             final UserInfo user;
             synchronized (mPackagesLock) {
-                user = mUsers.get(userHandle);
-                if (userHandle == 0 || user == null || mRemovingUserIds.get(userHandle)) {
-                    return false;
+                synchronized (mUsersLock) {
+                    user = mUsers.get(userHandle);
+                    if (userHandle == 0 || user == null || mRemovingUserIds.get(userHandle)) {
+                        return false;
+                    }
                 }
                 if (!user.isGuest()) {
                     return false;
@@ -1584,7 +1628,7 @@
                 // Mark it as disabled, so that it isn't returned any more when
                 // profiles are queried.
                 user.flags |= UserInfo.FLAG_DISABLED;
-                writeUserLocked(user);
+                writeUserLP(user);
             }
         } finally {
             Binder.restoreCallingIdentity(ident);
@@ -1614,15 +1658,17 @@
                 return false;
             }
             synchronized (mPackagesLock) {
-                user = mUsers.get(userHandle);
-                if (userHandle == 0 || user == null || mRemovingUserIds.get(userHandle)) {
-                    return false;
-                }
+                synchronized (mUsersLock) {
+                    user = mUsers.get(userHandle);
+                    if (userHandle == 0 || user == null || mRemovingUserIds.get(userHandle)) {
+                        return false;
+                    }
 
-                // We remember deleted user IDs to prevent them from being
-                // reused during the current boot; they can still be reused
-                // after a reboot.
-                mRemovingUserIds.put(userHandle, true);
+                    // We remember deleted user IDs to prevent them from being
+                    // reused during the current boot; they can still be reused
+                    // after a reboot.
+                    mRemovingUserIds.put(userHandle, true);
+                }
 
                 try {
                     mAppOpsService.removeUser(userHandle);
@@ -1636,7 +1682,7 @@
                 // Mark it as disabled, so that it isn't returned any more when
                 // profiles are queried.
                 user.flags |= UserInfo.FLAG_DISABLED;
-                writeUserLocked(user);
+                writeUserLP(user);
             }
 
             if (user.profileGroupId != UserInfo.NO_PROFILE_GROUP_ID
@@ -1694,7 +1740,7 @@
                                             .onUserRemoved(userHandle);
                                     synchronized (mInstallLock) {
                                         synchronized (mPackagesLock) {
-                                            removeUserStateLocked(userHandle);
+                                            removeUserStateLILP(userHandle);
                                         }
                                     }
                                 }
@@ -1708,20 +1754,22 @@
         }
     }
 
-    private void removeUserStateLocked(final int userHandle) {
+    private void removeUserStateLILP(final int userHandle) {
         mContext.getSystemService(StorageManager.class)
             .deleteUserKey(userHandle);
         // Cleanup package manager settings
         mPm.cleanUpUserLILPw(this, userHandle);
 
         // Remove this user from the list
-        mUsers.remove(userHandle);
+        synchronized (mUsersLock) {
+            mUsers.remove(userHandle);
+        }
         // Remove user file
         AtomicFile userFile = new AtomicFile(new File(mUsersDir, userHandle + XML_SUFFIX));
         userFile.delete();
         // Update the user list
-        writeUserListLocked();
-        updateUserIdsLocked();
+        writeUserListLILP();
+        updateUserIds();
         removeDirectoryRecursive(Environment.getUserSystemDirectory(userHandle));
     }
 
@@ -1757,7 +1805,7 @@
         }
         synchronized (mPackagesLock) {
             // Read the restrictions from XML
-            return readApplicationRestrictionsLocked(packageName, userId);
+            return readApplicationRestrictionsLP(packageName, userId);
         }
     }
 
@@ -1770,7 +1818,7 @@
                 cleanAppRestrictionsForPackage(packageName, userId);
             } else {
                 // Write the restrictions to XML
-                writeApplicationRestrictionsLocked(packageName, restrictions, userId);
+                writeApplicationRestrictionsLP(packageName, restrictions, userId);
             }
         }
 
@@ -1818,16 +1866,15 @@
         }
     }
 
-    private Bundle readApplicationRestrictionsLocked(String packageName,
-            int userId) {
+    private Bundle readApplicationRestrictionsLP(String packageName, int userId) {
         AtomicFile restrictionsFile =
                 new AtomicFile(new File(Environment.getUserSystemDirectory(userId),
                         packageToRestrictionsFileName(packageName)));
-        return readApplicationRestrictionsLocked(restrictionsFile);
+        return readApplicationRestrictionsLP(restrictionsFile);
     }
 
     @VisibleForTesting
-    static Bundle readApplicationRestrictionsLocked(AtomicFile restrictionsFile) {
+    static Bundle readApplicationRestrictionsLP(AtomicFile restrictionsFile) {
         final Bundle restrictions = new Bundle();
         final ArrayList<String> values = new ArrayList<>();
         if (!restrictionsFile.getBaseFile().exists()) {
@@ -1910,17 +1957,16 @@
         return childBundle;
     }
 
-    private void writeApplicationRestrictionsLocked(String packageName,
+    private void writeApplicationRestrictionsLP(String packageName,
             Bundle restrictions, int userId) {
         AtomicFile restrictionsFile = new AtomicFile(
                 new File(Environment.getUserSystemDirectory(userId),
                         packageToRestrictionsFileName(packageName)));
-        writeApplicationRestrictionsLocked(restrictions, restrictionsFile);
+        writeApplicationRestrictionsLP(restrictions, restrictionsFile);
     }
 
     @VisibleForTesting
-    static void writeApplicationRestrictionsLocked(Bundle restrictions,
-            AtomicFile restrictionsFile) {
+    static void writeApplicationRestrictionsLP(Bundle restrictions, AtomicFile restrictionsFile) {
         FileOutputStream fos = null;
         try {
             fos = restrictionsFile.startWrite();
@@ -1990,17 +2036,17 @@
 
     @Override
     public int getUserSerialNumber(int userHandle) {
-        synchronized (mPackagesLock) {
+        synchronized (mUsersLock) {
             if (!exists(userHandle)) return -1;
-            return getUserInfoLocked(userHandle).serialNumber;
+            return getUserInfoLU(userHandle).serialNumber;
         }
     }
 
     @Override
     public int getUserHandle(int userSerialNumber) {
-        synchronized (mPackagesLock) {
+        synchronized (mUsersLock) {
             for (int userId : mUserIds) {
-                UserInfo info = getUserInfoLocked(userId);
+                UserInfo info = getUserInfoLU(userId);
                 if (info != null && info.serialNumber == userSerialNumber) return userId;
             }
             // Not found
@@ -2012,13 +2058,13 @@
     public long getUserCreationTime(int userHandle) {
         int callingUserId = UserHandle.getCallingUserId();
         UserInfo userInfo = null;
-        synchronized (mPackagesLock) {
+        synchronized (mUsersLock) {
             if (callingUserId == userHandle) {
-                userInfo = getUserInfoLocked(userHandle);
+                userInfo = getUserInfoLU(userHandle);
             } else {
-                UserInfo parent = getProfileParentLocked(userHandle);
+                UserInfo parent = getProfileParentLU(userHandle);
                 if (parent != null && parent.id == callingUserId) {
-                    userInfo = getUserInfoLocked(userHandle);
+                    userInfo = getUserInfoLU(userHandle);
                 }
             }
         }
@@ -2032,22 +2078,24 @@
     /**
      * Caches the list of user ids in an array, adjusting the array size when necessary.
      */
-    private void updateUserIdsLocked() {
+    private void updateUserIds() {
         int num = 0;
-        final int userSize = mUsers.size();
-        for (int i = 0; i < userSize; i++) {
-            if (!mUsers.valueAt(i).partial) {
-                num++;
+        synchronized (mUsersLock) {
+            final int userSize = mUsers.size();
+            for (int i = 0; i < userSize; i++) {
+                if (!mUsers.valueAt(i).partial) {
+                    num++;
+                }
             }
-        }
-        final int[] newUsers = new int[num];
-        int n = 0;
-        for (int i = 0; i < userSize; i++) {
-            if (!mUsers.valueAt(i).partial) {
-                newUsers[n++] = mUsers.keyAt(i);
+            final int[] newUsers = new int[num];
+            int n = 0;
+            for (int i = 0; i < userSize; i++) {
+                if (!mUsers.valueAt(i).partial) {
+                    newUsers[n++] = mUsers.keyAt(i);
+                }
             }
+            mUserIds = newUsers;
         }
-        mUserIds = newUsers;
     }
 
     /**
@@ -2056,7 +2104,7 @@
      */
     public void onUserForeground(int userId) {
         synchronized (mPackagesLock) {
-            UserInfo user = mUsers.get(userId);
+            UserInfo user = getUserInfoNoChecks(userId);
             long now = System.currentTimeMillis();
             if (user == null || user.partial) {
                 Slog.w(LOG_TAG, "userForeground: unknown user #" + userId);
@@ -2064,7 +2112,7 @@
             }
             if (now > EPOCH_PLUS_30_YEARS) {
                 user.lastLoggedInTime = now;
-                scheduleWriteUserLocked(user);
+                scheduleWriteUserLP(user);
             }
         }
     }
@@ -2075,8 +2123,8 @@
      * for data and battery stats collection, or unexpected cross-talk.
      * @return
      */
-    private int getNextAvailableIdLocked() {
-        synchronized (mPackagesLock) {
+    private int getNextAvailableId() {
+        synchronized (mUsersLock) {
             int i = MIN_USER_ID;
             while (i < MAX_USER_ID) {
                 if (mUsers.indexOfKey(i) < 0 && !mRemovingUserIds.get(i)) {
@@ -2221,38 +2269,49 @@
         long now = System.currentTimeMillis();
         StringBuilder sb = new StringBuilder();
         synchronized (mPackagesLock) {
-            pw.println("Users:");
-            for (int i = 0; i < mUsers.size(); i++) {
-                UserInfo user = mUsers.valueAt(i);
-                if (user == null) continue;
-                pw.print("  "); pw.print(user); pw.print(" serialNo="); pw.print(user.serialNumber);
-                if (mRemovingUserIds.get(mUsers.keyAt(i))) pw.print(" <removing> ");
-                if (user.partial) pw.print(" <partial>");
-                pw.println();
-                pw.print("    Created: ");
-                if (user.creationTime == 0) {
-                    pw.println("<unknown>");
-                } else {
-                    sb.setLength(0);
-                    TimeUtils.formatDuration(now - user.creationTime, sb);
-                    sb.append(" ago");
-                    pw.println(sb);
+            synchronized (mUsersLock) {
+                pw.println("Users:");
+                for (int i = 0; i < mUsers.size(); i++) {
+                    UserInfo user = mUsers.valueAt(i);
+                    if (user == null) {
+                        continue;
+                    }
+                    pw.print("  "); pw.print(user);
+                    pw.print(" serialNo="); pw.print(user.serialNumber);
+                    if (mRemovingUserIds.get(mUsers.keyAt(i))) {
+                        pw.print(" <removing> ");
+                    }
+                    if (user.partial) {
+                        pw.print(" <partial>");
+                    }
+                    pw.println();
+                    pw.print("    Created: ");
+                    if (user.creationTime == 0) {
+                        pw.println("<unknown>");
+                    } else {
+                        sb.setLength(0);
+                        TimeUtils.formatDuration(now - user.creationTime, sb);
+                        sb.append(" ago");
+                        pw.println(sb);
+                    }
+                    pw.print("    Last logged in: ");
+                    if (user.lastLoggedInTime == 0) {
+                        pw.println("<unknown>");
+                    } else {
+                        sb.setLength(0);
+                        TimeUtils.formatDuration(now - user.lastLoggedInTime, sb);
+                        sb.append(" ago");
+                        pw.println(sb);
+                    }
+                    pw.println("    Restrictions:");
+                    synchronized (mRestrictionsLock) {
+                        UserRestrictionsUtils.dumpRestrictions(
+                                pw, "      ", mBaseUserRestrictions.get(user.id));
+                        pw.println("    Effective restrictions:");
+                        UserRestrictionsUtils.dumpRestrictions(
+                                pw, "      ", mCachedEffectiveUserRestrictions.get(user.id));
+                    }
                 }
-                pw.print("    Last logged in: ");
-                if (user.lastLoggedInTime == 0) {
-                    pw.println("<unknown>");
-                } else {
-                    sb.setLength(0);
-                    TimeUtils.formatDuration(now - user.lastLoggedInTime, sb);
-                    sb.append(" ago");
-                    pw.println(sb);
-                }
-                pw.println("    Restrictions:");
-                UserRestrictionsUtils.dumpRestrictions(
-                        pw, "      ", mBaseUserRestrictions.get(user.id));
-                pw.println("    Effective restrictions:");
-                UserRestrictionsUtils.dumpRestrictions(
-                        pw, "      ", mCachedEffectiveUserRestrictions.get(user.id));
             }
             pw.println();
             pw.println("Guest restrictions:");
@@ -2269,9 +2328,9 @@
                     removeMessages(WRITE_USER_MSG, msg.obj);
                     synchronized (mPackagesLock) {
                         int userId = ((UserInfo) msg.obj).id;
-                        UserInfo userInfo = mUsers.get(userId);
+                        UserInfo userInfo = getUserInfoNoChecks(userId);
                         if (userInfo != null) {
-                            writeUserLocked(userInfo);
+                            writeUserLP(userInfo);
                         }
                     }
             }
@@ -2295,14 +2354,14 @@
 
         @Override
         @GuardedBy("mRestrictionsLock")
-        public void updateEffectiveUserRestrictionsRL(int userId) {
-            UserManagerService.this.updateEffectiveUserRestrictionsRL(userId);
+        public void updateEffectiveUserRestrictionsLR(int userId) {
+            UserManagerService.this.updateEffectiveUserRestrictionsLR(userId);
         }
 
         @Override
         @GuardedBy("mRestrictionsLock")
-        public void updateEffectiveUserRestrictionsForAllUsersRL() {
-            UserManagerService.this.updateEffectiveUserRestrictionsForAllUsersRL();
+        public void updateEffectiveUserRestrictionsForAllUsersLR() {
+            UserManagerService.this.updateEffectiveUserRestrictionsForAllUsersLR();
         }
 
         @Override
@@ -2317,13 +2376,13 @@
                 int userId, Bundle baseRestrictions) {
             synchronized (mRestrictionsLock) {
                 mBaseUserRestrictions.put(userId, new Bundle(baseRestrictions));
-                invalidateEffectiveUserRestrictionsRL(userId);
+                invalidateEffectiveUserRestrictionsLR(userId);
             }
 
+            final UserInfo userInfo = getUserInfoNoChecks(userId);
             synchronized (mPackagesLock) {
-                final UserInfo userInfo = mUsers.get(userId);
                 if (userInfo != null) {
-                    writeUserLocked(userInfo);
+                    writeUserLP(userInfo);
                 } else {
                     Slog.w(LOG_TAG, "UserInfo not found for " + userId);
                 }
diff --git a/services/core/java/com/android/server/webkit/WebViewUpdateService.java b/services/core/java/com/android/server/webkit/WebViewUpdateService.java
index d4c5f87..ac79b36 100644
--- a/services/core/java/com/android/server/webkit/WebViewUpdateService.java
+++ b/services/core/java/com/android/server/webkit/WebViewUpdateService.java
@@ -40,6 +40,8 @@
     private boolean mRelroReady32Bit = false;
     private boolean mRelroReady64Bit = false;
 
+    private String oldWebViewPackageName = null;
+
     private BroadcastReceiver mWebViewUpdatedReceiver;
 
     public WebViewUpdateService(Context context) {
@@ -51,9 +53,22 @@
         mWebViewUpdatedReceiver = new BroadcastReceiver() {
                 @Override
                 public void onReceive(Context context, Intent intent) {
-                    String webviewPackage = "package:" + WebViewFactory.getWebViewPackageName();
-                    if (webviewPackage.equals(intent.getDataString())) {
-                        onWebViewUpdateInstalled();
+
+                    for (String packageName : WebViewFactory.getWebViewPackageNames()) {
+                        String webviewPackage = "package:" + packageName;
+
+                        if (webviewPackage.equals(intent.getDataString())) {
+                            String usedPackageName =
+                                WebViewFactory.findPreferredWebViewPackage().packageName;
+                            // Only trigger update actions if the updated package is the one that
+                            // will be used, or the one that was in use before the update.
+                            if (packageName.equals(usedPackageName) ||
+                                    packageName.equals(oldWebViewPackageName)) {
+                                onWebViewUpdateInstalled();
+                                oldWebViewPackageName = usedPackageName;
+                            }
+                            return;
+                        }
                     }
                 }
         };
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 1602c12..aea2ecf 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -1064,8 +1064,7 @@
         if (removed) {
             synchronized (mUserManagerInternal.getUserRestrictionsLock()) {
                 synchronized (DevicePolicyManagerService.this) {
-                    mUserManagerInternal.updateEffectiveUserRestrictionsRL(
-                            userHandle);
+                    mUserManagerInternal.updateEffectiveUserRestrictionsLR(userHandle);
                 }
             }
         }
@@ -1718,7 +1717,7 @@
                             }
                             synchronized (mUserManagerInternal.getUserRestrictionsLock()) {
                                 synchronized (DevicePolicyManagerService.this) {
-                                    mUserManagerInternal.updateEffectiveUserRestrictionsRL(
+                                    mUserManagerInternal.updateEffectiveUserRestrictionsLR(
                                             userHandle);
                                 }
                             }
@@ -4337,9 +4336,9 @@
         synchronized (mUserManagerInternal.getUserRestrictionsLock()) {
             synchronized (this) {
                 if (isDeviceOwner(who)) {
-                    mUserManagerInternal.updateEffectiveUserRestrictionsForAllUsersRL();
+                    mUserManagerInternal.updateEffectiveUserRestrictionsForAllUsersLR();
                 } else {
-                    mUserManagerInternal.updateEffectiveUserRestrictionsRL(userHandle);
+                    mUserManagerInternal.updateEffectiveUserRestrictionsLR(userHandle);
                 }
             }
         }
@@ -4651,7 +4650,7 @@
                     0  /* flagValues */, userHandle.getIdentifier());
             // TODO This will not revert audio mute restrictions if they were set.  b/24981972
             synchronized (mUserManagerInternal.getUserRestrictionsLock()) {
-                mUserManagerInternal.updateEffectiveUserRestrictionsRL(userHandle.getIdentifier());
+                mUserManagerInternal.updateEffectiveUserRestrictionsLR(userHandle.getIdentifier());
             }
         } catch (RemoteException re) {
         } finally {
@@ -5628,9 +5627,9 @@
 
                     // Tell UserManager the new value.
                     if (isDeviceOwner) {
-                        mUserManagerInternal.updateEffectiveUserRestrictionsForAllUsersRL();
+                        mUserManagerInternal.updateEffectiveUserRestrictionsForAllUsersLR();
                     } else {
-                        mUserManagerInternal.updateEffectiveUserRestrictionsRL(userHandle);
+                        mUserManagerInternal.updateEffectiveUserRestrictionsLR(userHandle);
                     }
                 } finally {
                     mInjector.binderRestoreCallingIdentity(id);
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceTest.java
index eb7eb15..9e70138 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceTest.java
@@ -46,11 +46,11 @@
     public void testWriteReadApplicationRestrictions() throws IOException {
         AtomicFile atomicFile = new AtomicFile(restrictionsFile);
         Bundle bundle = createBundle();
-        UserManagerService.writeApplicationRestrictionsLocked(bundle, atomicFile);
+        UserManagerService.writeApplicationRestrictionsLP(bundle, atomicFile);
         assertTrue(atomicFile.getBaseFile().exists());
         String s = FileUtils.readTextFile(restrictionsFile, 10000, "");
         System.out.println("restrictionsFile: " + s);
-        bundle = UserManagerService.readApplicationRestrictionsLocked(atomicFile);
+        bundle = UserManagerService.readApplicationRestrictionsLP(atomicFile);
         System.out.println("readApplicationRestrictionsLocked bundle: " + bundle);
         assertBundle(bundle);
     }
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java
index 2997907..11bd15d 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java
@@ -95,6 +95,13 @@
     }
 
     @Override
+    public void repositionChild(IWindow childWindow, int x, int y, long deferTransactionUntilFrame,
+            Rect outFrame) {
+        // pass for now.
+        return;
+    }
+
+    @Override
     public void performDeferredDestroy(IWindow window) {
         // pass for now.
     }