OMS: Setup state for users on boot and when added
Some users never get switched to (managed profile/work profile) so the
overlay state for a user would never be setup (but they could still show
UI and apps).
This change ensures that user state is setup after an OTA to android O,
and whenever a user is added.
Bug: 37899201
Test: manual (add user via Device Admin sample: vendor/google/tools/DeviceAdminSample)
Change-Id: If214e26e39b18c2861794baf5c608a47d536e5ff
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index f2df7da..7bd3bf6 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -19,6 +19,7 @@
import android.Manifest;
import android.accounts.AccountManager;
import android.annotation.IntDef;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
@@ -2129,7 +2130,7 @@
* @return the list of users that were created.
* @hide
*/
- public List<UserInfo> getUsers(boolean excludeDying) {
+ public @NonNull List<UserInfo> getUsers(boolean excludeDying) {
try {
return mService.getUsers(excludeDying);
} catch (RemoteException re) {
diff --git a/services/core/java/com/android/server/om/OverlayManagerService.java b/services/core/java/com/android/server/om/OverlayManagerService.java
index 0e1f485..ef3e7bc 100644
--- a/services/core/java/com/android/server/om/OverlayManagerService.java
+++ b/services/core/java/com/android/server/om/OverlayManagerService.java
@@ -20,6 +20,7 @@
import static android.content.Intent.ACTION_PACKAGE_ADDED;
import static android.content.Intent.ACTION_PACKAGE_CHANGED;
import static android.content.Intent.ACTION_PACKAGE_REMOVED;
+import static android.content.Intent.ACTION_USER_ADDED;
import static android.content.Intent.ACTION_USER_REMOVED;
import static android.content.pm.PackageManager.SIGNATURE_MATCH;
@@ -46,6 +47,7 @@
import android.os.ShellCallback;
import android.os.SystemProperties;
import android.os.UserHandle;
+import android.os.UserManager;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
@@ -243,11 +245,14 @@
packageFilter, null, null);
final IntentFilter userFilter = new IntentFilter();
+ userFilter.addAction(ACTION_USER_ADDED);
userFilter.addAction(ACTION_USER_REMOVED);
getContext().registerReceiverAsUser(new UserReceiver(), UserHandle.ALL,
userFilter, null, null);
restoreSettings();
+
+ initIfNeeded();
onSwitchUser(UserHandle.USER_SYSTEM);
publishBinderService(Context.OVERLAY_SERVICE, mService);
@@ -269,14 +274,31 @@
}
}
+ private void initIfNeeded() {
+ final UserManager um = getContext().getSystemService(UserManager.class);
+ final List<UserInfo> users = um.getUsers(true /*excludeDying*/);
+ synchronized (mLock) {
+ final int userCount = users.size();
+ for (int i = 0; i < userCount; i++) {
+ final UserInfo userInfo = users.get(i);
+ if (!userInfo.supportsSwitchTo() && userInfo.id != UserHandle.USER_SYSTEM) {
+ // Initialize any users that can't be switched to, as there state would
+ // never be setup in onSwitchUser(). We will switch to the system user right
+ // after this, and its state will be setup there.
+ final List<String> targets = mImpl.updateOverlaysForUser(users.get(i).id);
+ updateOverlayPaths(users.get(i).id, targets);
+ }
+ }
+ }
+ }
+
@Override
public void onSwitchUser(final int newUserId) {
// ensure overlays in the settings are up-to-date, and propagate
// any asset changes to the rest of the system
- final List<String> targets;
synchronized (mLock) {
- targets = mImpl.onSwitchUser(newUserId);
- updateAssetsLocked(newUserId, targets);
+ final List<String> targets = mImpl.updateOverlaysForUser(newUserId);
+ updateAssets(newUserId, targets);
}
schedulePersistSettings();
}
@@ -428,10 +450,19 @@
private final class UserReceiver extends BroadcastReceiver {
@Override
public void onReceive(@NonNull final Context context, @NonNull final Intent intent) {
+ final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
switch (intent.getAction()) {
+ case ACTION_USER_ADDED:
+ if (userId != UserHandle.USER_NULL) {
+ final ArrayList<String> targets;
+ synchronized (mLock) {
+ targets = mImpl.updateOverlaysForUser(userId);
+ }
+ updateOverlayPaths(userId, targets);
+ }
+ break;
+
case ACTION_USER_REMOVED:
- final int userId =
- intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
if (userId != UserHandle.USER_NULL) {
synchronized (mLock) {
mImpl.onUserRemoved(userId);
@@ -647,9 +678,7 @@
public void onOverlaysChanged(@NonNull final String targetPackageName, final int userId) {
schedulePersistSettings();
FgThread.getHandler().post(() -> {
- synchronized (mLock) {
- updateAssetsLocked(userId, targetPackageName);
- }
+ updateAssets(userId, targetPackageName);
final Intent intent = new Intent(Intent.ACTION_OVERLAY_CHANGED,
Uri.fromParts("package", targetPackageName, null));
@@ -670,13 +699,10 @@
}
}
- private void updateAssetsLocked(final int userId, final String targetPackageName) {
- final List<String> list = new ArrayList<>();
- list.add(targetPackageName);
- updateAssetsLocked(userId, list);
- }
-
- private void updateAssetsLocked(final int userId, List<String> targetPackageNames) {
+ /**
+ * Updates the target packages' set of enabled overlays in PackageManager.
+ */
+ private void updateOverlayPaths(int userId, List<String> targetPackageNames) {
if (DEBUG) {
Slog.d(TAG, "Updating overlay assets");
}
@@ -706,12 +732,19 @@
}
if (!pm.setEnabledOverlayPackages(
- userId, targetPackageName, pendingChanges.get(targetPackageName))) {
+ userId, targetPackageName, pendingChanges.get(targetPackageName))) {
Slog.e(TAG, String.format("Failed to change enabled overlays for %s user %d",
- targetPackageName, userId));
+ targetPackageName, userId));
}
}
+ }
+ private void updateAssets(final int userId, final String targetPackageName) {
+ updateAssets(userId, Collections.singletonList(targetPackageName));
+ }
+
+ private void updateAssets(final int userId, List<String> targetPackageNames) {
+ updateOverlayPaths(userId, targetPackageNames);
final IActivityManager am = ActivityManager.getService();
try {
am.scheduleApplicationInfoChanged(targetPackageNames, userId);
diff --git a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
index 5196c66..261bcc5 100644
--- a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
+++ b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
@@ -68,15 +68,15 @@
mListener = listener;
}
- /*
- * Call this when switching to a new Android user. Will return a list of
- * target packages that must refresh their overlays. This list is the union
+ /**
+ * Call this to synchronize the Settings for a user with what PackageManager knows about a user.
+ * Returns a list of target packages that must refresh their overlays. This list is the union
* of two sets: the set of targets with currently active overlays, and the
* set of targets that had, but no longer have, active overlays.
*/
- List<String> onSwitchUser(final int newUserId) {
+ ArrayList<String> updateOverlaysForUser(final int newUserId) {
if (DEBUG) {
- Slog.d(TAG, "onSwitchUser newUserId=" + newUserId);
+ Slog.d(TAG, "updateOverlaysForUser newUserId=" + newUserId);
}
final Set<String> packagesToUpdateAssets = new ArraySet<>();
diff --git a/services/core/java/com/android/server/om/OverlayManagerSettings.java b/services/core/java/com/android/server/om/OverlayManagerSettings.java
index 2f83793..353b710 100644
--- a/services/core/java/com/android/server/om/OverlayManagerSettings.java
+++ b/services/core/java/com/android/server/om/OverlayManagerSettings.java
@@ -22,12 +22,14 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.om.OverlayInfo;
+import android.os.UserHandle;
import android.util.AndroidRuntimeException;
import android.util.ArrayMap;
import android.util.Slog;
import android.util.Xml;
import com.android.internal.util.FastXmlSerializer;
+import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.XmlUtils;
import org.xmlpull.v1.XmlPullParser;
@@ -266,32 +268,32 @@
return true;
}
- private static final String TAB1 = " ";
- private static final String TAB2 = TAB1 + TAB1;
- private static final String TAB3 = TAB2 + TAB1;
-
- void dump(@NonNull final PrintWriter pw) {
+ void dump(@NonNull final PrintWriter p) {
+ final IndentingPrintWriter pw = new IndentingPrintWriter(p, " ");
pw.println("Settings");
- pw.println(TAB1 + "Items");
+ pw.increaseIndent();
if (mItems.isEmpty()) {
- pw.println(TAB2 + "<none>");
+ pw.println("<none>");
return;
}
final int N = mItems.size();
for (int i = 0; i < N; i++) {
final SettingsItem item = mItems.get(i);
- final StringBuilder sb = new StringBuilder();
- sb.append(TAB2 + item.mPackageName + ":" + item.getUserId() + " {\n");
- sb.append(TAB3 + "mPackageName.......: " + item.mPackageName + "\n");
- sb.append(TAB3 + "mUserId............: " + item.getUserId() + "\n");
- sb.append(TAB3 + "mTargetPackageName.: " + item.getTargetPackageName() + "\n");
- sb.append(TAB3 + "mBaseCodePath......: " + item.getBaseCodePath() + "\n");
- sb.append(TAB3 + "mState.............: " + OverlayInfo.stateToString(item.getState()) + "\n");
- sb.append(TAB3 + "mIsEnabled.........: " + item.isEnabled() + "\n");
- sb.append(TAB2 + "}");
- pw.println(sb.toString());
+ pw.println(item.mPackageName + ":" + item.getUserId() + " {");
+ pw.increaseIndent();
+
+ pw.print("mPackageName.......: "); pw.println(item.mPackageName);
+ pw.print("mUserId............: "); pw.println(item.getUserId());
+ pw.print("mTargetPackageName.: "); pw.println(item.getTargetPackageName());
+ pw.print("mBaseCodePath......: "); pw.println(item.getBaseCodePath());
+ pw.print("mState.............: "); pw.println(OverlayInfo.stateToString(item.getState()));
+ pw.print("mIsEnabled.........: "); pw.println(item.isEnabled());
+ pw.print("mIsStatic..........: "); pw.println(item.isStatic());
+
+ pw.decreaseIndent();
+ pw.println("}");
}
}
@@ -527,12 +529,6 @@
.filter(item -> item.getTargetPackageName().equals(targetPackageName));
}
- private void assertNotNull(@Nullable final Object o) {
- if (o == null) {
- throw new AndroidRuntimeException("object must not be null");
- }
- }
-
static final class BadKeyException extends RuntimeException {
BadKeyException(@NonNull final String packageName, final int userId) {
super("Bad key mPackageName=" + packageName + " mUserId=" + userId);