From 708703bf39801027b616bcc43c650889bf0ef571 Mon Sep 17 00:00:00 2001 From: Makoto Onuki Date: Mon, 11 Dec 2017 16:38:11 -0800 Subject: [PATCH] Avoid strict mode violation in shortcut manager on user-unlock - The issue is the shortcut host information was stored in ShortcutUser, which is per-user shortcut information that's persisted in the disk. Even though in the onUnlockUser sequence we only need to "set" a package name, in order to access the ShortcutUser instance for the target user, we'd need to load the per-user information from the disk. - Luckily the host packages don't need to be persisted, so let's just move it to another structure which is just kept in memory. Bug: 70526858 Test: Manual test (boot, unlock user, unlock secondary user) Test: adb shell am instrument -w -e class com.android.server.pm.ShortcutManagerTest1 -w com.android.frameworks.servicestests Test: adb shell am instrument -w -e class com.android.server.pm.ShortcutManagerTest2 -w com.android.frameworks.servicestests Test: adb shell am instrument -w -e class com.android.server.pm.ShortcutManagerTest3 -w com.android.frameworks.servicestests Test: adb shell am instrument -w -e class com.android.server.pm.ShortcutManagerTest4 -w com.android.frameworks.servicestests Test: adb shell am instrument -w -e class com.android.server.pm.ShortcutManagerTest5 -w com.android.frameworks.servicestests Test: adb shell am instrument -w -e class com.android.server.pm.ShortcutManagerTest6 -w com.android.frameworks.servicestests Test: adb shell am instrument -w -e class com.android.server.pm.ShortcutManagerTest7 -w com.android.frameworks.servicestests Test: adb shell am instrument -w -e class com.android.server.pm.ShortcutManagerTest8 -w com.android.frameworks.servicestests Test: adb shell am instrument -w -e class com.android.server.pm.ShortcutManagerTest9 -w com.android.frameworks.servicestests Test: adb shell am instrument -w -e class com.android.server.pm.ShortcutManagerTest10 -w com.android.frameworks.servicestests Test: cts-tradefed run cts-dev --skip-device-info --skip-preconditions --skip-system-status-check com.android.compatibility.common.tradefed.targetprep.NetworkConnectivityChecker -a armeabi-v7a -l INFO -m CtsShortcutManagerTestCases Change-Id: Ic4b842c4a3a08a7f0e678ce328e9d4ee08fd4069 --- .../server/pm/ShortcutNonPersistentUser.java | 98 ++++++++++++++++++++++ .../com/android/server/pm/ShortcutService.java | 34 ++++++-- .../java/com/android/server/pm/ShortcutUser.java | 43 ---------- 3 files changed, 127 insertions(+), 48 deletions(-) create mode 100644 services/core/java/com/android/server/pm/ShortcutNonPersistentUser.java diff --git a/services/core/java/com/android/server/pm/ShortcutNonPersistentUser.java b/services/core/java/com/android/server/pm/ShortcutNonPersistentUser.java new file mode 100644 index 000000000000..7f6f684e0b68 --- /dev/null +++ b/services/core/java/com/android/server/pm/ShortcutNonPersistentUser.java @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2017 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.server.pm; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.util.ArrayMap; +import android.util.ArraySet; + +import com.android.server.pm.ShortcutService.DumpFilter; + +import java.io.PrintWriter; + +/** + * This class holds per-user information for {@link ShortcutService} that doesn't have to be + * persisted and is kept in-memory. + * + * The access to it must be guarded with the shortcut manager lock. + */ +public class ShortcutNonPersistentUser { + private final ShortcutService mService; + + private final int mUserId; + + /** + * Keep track of additional packages that other parts of the system have said are + * allowed to access shortcuts. The key is the part of the system it came from, + * the value is the package name that has access. We don't persist these because + * at boot all relevant system services will push this data back to us they do their + * normal evaluation of the state of the world. + */ + private final ArrayMap mHostPackages = new ArrayMap<>(); + + /** + * Set of package name values from above. + */ + private final ArraySet mHostPackageSet = new ArraySet<>(); + + public ShortcutNonPersistentUser(ShortcutService service, int userId) { + mService = service; + mUserId = userId; + } + + public int getUserId() { + return mUserId; + } + + public void setShortcutHostPackage(@NonNull String type, @Nullable String packageName) { + if (packageName != null) { + mHostPackages.put(type, packageName); + } else { + mHostPackages.remove(type); + } + + mHostPackageSet.clear(); + for (int i = 0; i < mHostPackages.size(); i++) { + mHostPackageSet.add(mHostPackages.valueAt(i)); + } + } + + public boolean hasHostPackage(@NonNull String packageName) { + return mHostPackageSet.contains(packageName); + } + + public void dump(@NonNull PrintWriter pw, @NonNull String prefix, DumpFilter filter) { + if (filter.shouldDumpDetails()) { + if (mHostPackages.size() > 0) { + pw.print(prefix); + pw.print("Non-persistent: user ID:"); + pw.println(mUserId); + + pw.print(prefix); + pw.println(" Host packages:"); + for (int i = 0; i < mHostPackages.size(); i++) { + pw.print(prefix); + pw.print(" "); + pw.print(mHostPackages.keyAt(i)); + pw.print(": "); + pw.println(mHostPackages.valueAt(i)); + } + pw.println(); + } + } + } +} diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java index ee2f3742c811..2a581530a68a 100644 --- a/services/core/java/com/android/server/pm/ShortcutService.java +++ b/services/core/java/com/android/server/pm/ShortcutService.java @@ -280,6 +280,13 @@ public class ShortcutService extends IShortcutService.Stub { private final SparseArray mUsers = new SparseArray<>(); /** + * User ID -> ShortcutNonPersistentUser + */ + @GuardedBy("mLock") + private final SparseArray mShortcutNonPersistentUsers = + new SparseArray<>(); + + /** * Max number of dynamic + manifest shortcuts that each application can have at a time. */ private int mMaxShortcuts; @@ -1199,6 +1206,18 @@ public class ShortcutService extends IShortcutService.Stub { return userPackages; } + /** Return the non-persistent per-user state. */ + @GuardedBy("mLock") + @NonNull + ShortcutNonPersistentUser getNonPersistentUserLocked(@UserIdInt int userId) { + ShortcutNonPersistentUser ret = mShortcutNonPersistentUsers.get(userId); + if (ret == null) { + ret = new ShortcutNonPersistentUser(this, userId); + mShortcutNonPersistentUsers.put(userId, ret); + } + return ret; + } + void forEachLoadedUserLocked(@NonNull Consumer c) { for (int i = mUsers.size() - 1; i >= 0; i--) { c.accept(mUsers.valueAt(i)); @@ -2251,7 +2270,7 @@ public class ShortcutService extends IShortcutService.Stub { return true; } synchronized (mLock) { - return getUserShortcutsLocked(userId).hasHostPackage(callingPackage); + return getNonPersistentUserLocked(userId).hasHostPackage(callingPackage); } } @@ -2375,10 +2394,7 @@ public class ShortcutService extends IShortcutService.Stub { public void setShortcutHostPackage(@NonNull String type, @Nullable String packageName, int userId) { synchronized (mLock) { - throwIfUserLockedL(userId); - - final ShortcutUser user = getUserShortcutsLocked(userId); - user.setShortcutHostPackage(type, packageName); + getNonPersistentUserLocked(userId).setShortcutHostPackage(type, packageName); } } @@ -3836,6 +3852,14 @@ public class ShortcutService extends IShortcutService.Stub { pw.println(); } } + + for (int i = 0; i < mShortcutNonPersistentUsers.size(); i++) { + final ShortcutNonPersistentUser user = mShortcutNonPersistentUsers.valueAt(i); + if (filter.isUserMatch(user.getUserId())) { + user.dump(pw, " ", filter); + pw.println(); + } + } } } diff --git a/services/core/java/com/android/server/pm/ShortcutUser.java b/services/core/java/com/android/server/pm/ShortcutUser.java index 1efd765b18fa..b7247df3b2a1 100644 --- a/services/core/java/com/android/server/pm/ShortcutUser.java +++ b/services/core/java/com/android/server/pm/ShortcutUser.java @@ -124,20 +124,6 @@ class ShortcutUser { /** In-memory-cached default launcher. */ private ComponentName mCachedLauncher; - /** - * Keep track of additional packages that other parts of the system have said are - * allowed to access shortcuts. The key is the part of the system it came from, - * the value is the package name that has access. We don't persist these because - * at boot all relevant system services will push this data back to us they do their - * normal evaluation of the state of the world. - */ - private final ArrayMap mHostPackages = new ArrayMap<>(); - - /** - * Set of package name values from above. - */ - private final ArraySet mHostPackageSet = new ArraySet<>(); - private String mKnownLocales; private long mLastAppScanTime; @@ -482,23 +468,6 @@ class ShortcutUser { return mCachedLauncher; } - public void setShortcutHostPackage(@NonNull String type, @Nullable String packageName) { - if (packageName != null) { - mHostPackages.put(type, packageName); - } else { - mHostPackages.remove(type); - } - - mHostPackageSet.clear(); - for (int i = 0; i < mHostPackages.size(); i++) { - mHostPackageSet.add(mHostPackages.valueAt(i)); - } - } - - public boolean hasHostPackage(@NonNull String packageName) { - return mHostPackageSet.contains(packageName); - } - public void resetThrottling() { for (int i = mPackages.size() - 1; i >= 0; i--) { mPackages.valueAt(i).resetThrottling(); @@ -587,18 +556,6 @@ class ShortcutUser { pw.print("Last known launcher: "); pw.print(mLastKnownLauncher); pw.println(); - - if (mHostPackages.size() > 0) { - pw.print(prefix); - pw.println("Host packages:"); - for (int i = 0; i < mHostPackages.size(); i++) { - pw.print(prefix); - pw.print(" "); - pw.print(mHostPackages.keyAt(i)); - pw.print(": "); - pw.println(mHostPackages.valueAt(i)); - } - } } for (int i = 0; i < mLaunchers.size(); i++) { -- 2.11.0