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.
}