summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Makoto Onuki <omakoto@google.com> 2016-07-13 17:09:36 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2016-07-13 17:09:37 +0000
commit98802f6007eef7a36237087111c38a998a388903 (patch)
tree28df8b74b6f4472830d511f4136e1834d4483687
parent2061ff11c4030e86b9a2938aeb6493ff40beea23 (diff)
parent886ba78dfb105eb45416587b73b6c6b336448de5 (diff)
Merge "Revert "Revert "Handle package broadcasts before apps do""" into nyc-mr1-dev
-rw-r--r--core/java/android/content/pm/ShortcutServiceInternal.java7
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java8
-rw-r--r--services/core/java/com/android/server/pm/ShortcutPendingTasks.java159
-rw-r--r--services/core/java/com/android/server/pm/ShortcutService.java198
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java7
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java117
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest3.java2
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/ShortcutPendingTasksTest.java123
8 files changed, 507 insertions, 114 deletions
diff --git a/core/java/android/content/pm/ShortcutServiceInternal.java b/core/java/android/content/pm/ShortcutServiceInternal.java
index 3f8bad15035b..de52f73fc213 100644
--- a/core/java/android/content/pm/ShortcutServiceInternal.java
+++ b/core/java/android/content/pm/ShortcutServiceInternal.java
@@ -73,4 +73,11 @@ public abstract class ShortcutServiceInternal {
* any locks in this method.
*/
public abstract void onSystemLocaleChangedNoLock();
+
+ /**
+ * Called by PM before sending package broadcasts to other components. PM doesn't hold the PM
+ * lock, but do not take any locks in here anyway, and don't do any heavy tasks, as doing so
+ * would slow down all the package broadcasts.
+ */
+ public abstract void onPackageBroadcast(Intent intent);
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 5980715c5358..1ca61480973a 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -159,6 +159,7 @@ import android.content.pm.PermissionInfo;
import android.content.pm.ProviderInfo;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
+import android.content.pm.ShortcutServiceInternal;
import android.content.pm.Signature;
import android.content.pm.UserInfo;
import android.content.pm.VerifierDeviceIdentity;
@@ -11438,6 +11439,9 @@ public class PackageManagerService extends IPackageManager.Stub {
} else {
resolvedUserIds = userIds;
}
+ final ShortcutServiceInternal shortcutService =
+ LocalServices.getService(ShortcutServiceInternal.class);
+
for (int id : resolvedUserIds) {
final Intent intent = new Intent(action,
pkg != null ? Uri.fromParts("package", pkg, null) : null);
@@ -11462,6 +11466,10 @@ public class PackageManagerService extends IPackageManager.Stub {
+ intent.toShortString(false, true, false, false)
+ " " + intent.getExtras(), here);
}
+ // TODO b/29385425 Consider making lifecycle callbacks for this.
+ if (shortcutService != null) {
+ shortcutService.onPackageBroadcast(intent);
+ }
am.broadcastIntent(null, intent, null, finishedReceiver,
0, null, null, null, android.app.AppOpsManager.OP_NONE,
null, finishedReceiver != null, false, id);
diff --git a/services/core/java/com/android/server/pm/ShortcutPendingTasks.java b/services/core/java/com/android/server/pm/ShortcutPendingTasks.java
new file mode 100644
index 000000000000..a5ace56fee1f
--- /dev/null
+++ b/services/core/java/com/android/server/pm/ShortcutPendingTasks.java
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2016 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.util.Slog;
+
+import java.io.PrintWriter;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.function.BooleanSupplier;
+import java.util.function.Consumer;
+import java.util.logging.Handler;
+
+/**
+ * Used by {@link ShortcutService} to register tasks to be executed on Handler and also wait for
+ * all pending tasks.
+ *
+ * Tasks can be registered with {@link #addTask(Runnable)}. Call {@link #waitOnAllTasks()} to wait
+ * on all tasks that have been registered.
+ *
+ * In order to avoid deadlocks, {@link #waitOnAllTasks} MUST NOT be called with any lock held, nor
+ * on the handler thread. These conditions are checked by {@link #mWaitThreadChecker} and wtf'ed.
+ *
+ * During unit tests, we can't run tasks asynchronously, so we just run Runnables synchronously,
+ * which also means the "is lock held" check doesn't work properly during unit tests (e.g. normally
+ * when a Runnable is executed on a Handler, the thread doesn't hold any lock, but during the tests
+ * we just run a Runnable on the thread that registers it, so the thread may or may not hold locks.)
+ * So unfortunately we have to disable {@link #mWaitThreadChecker} during unit tests.
+ *
+ * Because of the complications like those, this class should be used only for specific purposes:
+ * - {@link #addTask(Runnable)} should only be used to register tasks on callbacks from lower level
+ * services like the package manager or the activity manager.
+ *
+ * - {@link #waitOnAllTasks} should only be called at the entry point of RPC calls (or the test only
+ * accessors}.
+ */
+public class ShortcutPendingTasks {
+ private static final String TAG = "ShortcutPendingTasks";
+
+ private static final boolean DEBUG = false || ShortcutService.DEBUG; // DO NOT SUBMIT WITH TRUE.
+
+ private final Consumer<Runnable> mRunner;
+
+ private final BooleanSupplier mWaitThreadChecker;
+
+ private final Consumer<Throwable> mExceptionHandler;
+
+ /** # of tasks in the queue, including the running one. */
+ private final AtomicInteger mRunningTaskCount = new AtomicInteger();
+
+ /** For dumpsys */
+ private final AtomicLong mLastTaskStartTime = new AtomicLong();
+
+ /**
+ * Constructor. In order to allow injection during unit tests, it doesn't take a
+ * {@link Handler} directly, and instead takes {@code runner} which will post an argument
+ * to a handler.
+ */
+ public ShortcutPendingTasks(Consumer<Runnable> runner, BooleanSupplier waitThreadChecker,
+ Consumer<Throwable> exceptionHandler) {
+ mRunner = runner;
+ mWaitThreadChecker = waitThreadChecker;
+ mExceptionHandler = exceptionHandler;
+ }
+
+ private static void dlog(String message) {
+ if (DEBUG) {
+ Slog.d(TAG, message);
+ }
+ }
+
+ /**
+ * Block until all tasks that are already queued finish. DO NOT call it while holding any lock
+ * or on the handler thread.
+ */
+ public boolean waitOnAllTasks() {
+ dlog("waitOnAllTasks: enter");
+ try {
+ // Make sure it's not holding the lock.
+ if (!mWaitThreadChecker.getAsBoolean()) {
+ return false;
+ }
+
+ // Optimize for the no-task case.
+ if (mRunningTaskCount.get() == 0) {
+ return true;
+ }
+
+ final CountDownLatch latch = new CountDownLatch(1);
+
+ addTask(latch::countDown);
+
+ for (; ; ) {
+ try {
+ if (latch.await(1, TimeUnit.SECONDS)) {
+ return true;
+ }
+ dlog("waitOnAllTasks: Task(s) still running...");
+ } catch (InterruptedException ignore) {
+ }
+ }
+ } finally {
+ dlog("waitOnAllTasks: exit");
+ }
+ }
+
+ /**
+ * Add a new task. This operation is lock-free.
+ */
+ public void addTask(Runnable task) {
+ mRunningTaskCount.incrementAndGet();
+ mLastTaskStartTime.set(System.currentTimeMillis());
+
+ dlog("Task registered");
+
+ mRunner.accept(() -> {
+ try {
+ dlog("Task started");
+
+ task.run();
+ } catch (Throwable th) {
+ mExceptionHandler.accept(th);
+ } finally {
+ dlog("Task finished");
+ mRunningTaskCount.decrementAndGet();
+ }
+ });
+ }
+
+ public void dump(@NonNull PrintWriter pw, @NonNull String prefix) {
+ pw.print(prefix);
+ pw.print("Pending tasks: # running tasks: ");
+ pw.println(mRunningTaskCount.get());
+
+ pw.print(prefix);
+ pw.print(" Last task started time: ");
+ final long lastStarted = mLastTaskStartTime.get();
+ pw.print(" [");
+ pw.print(lastStarted);
+ pw.print("] ");
+ pw.println(ShortcutService.formatTime(lastStarted));
+ }
+}
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index 5f8cbbf0544b..a9018b3a5a84 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -49,6 +49,7 @@ import android.graphics.Bitmap.CompressFormat;
import android.graphics.Canvas;
import android.graphics.RectF;
import android.graphics.drawable.Icon;
+import android.net.Uri;
import android.os.Binder;
import android.os.Environment;
import android.os.FileUtils;
@@ -81,7 +82,6 @@ import android.view.IWindowManager;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.content.PackageMonitor;
import com.android.internal.os.BackgroundThread;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.Preconditions;
@@ -122,9 +122,6 @@ import java.util.function.Predicate;
/**
* TODO:
- * - Deal with the async nature of PACKAGE_ADD. Basically when a publisher does anything after
- * it's upgraded, the manager should make sure the upgrade process has been executed.
- *
* - getIconMaxWidth()/getIconMaxHeight() should use xdpi and ydpi.
* -> But TypedValue.applyDimension() doesn't differentiate x and y..?
*
@@ -304,6 +301,8 @@ public class ShortcutService extends IShortcutService.Stub {
private final AtomicBoolean mBootCompleted = new AtomicBoolean();
+ private final ShortcutPendingTasks mPendingTasks;
+
private static final int PACKAGE_MATCH_FLAGS =
PackageManager.MATCH_DIRECT_BOOT_AWARE
| PackageManager.MATCH_DIRECT_BOOT_UNAWARE
@@ -377,16 +376,41 @@ public class ShortcutService extends IShortcutService.Stub {
mUsageStatsManagerInternal = Preconditions.checkNotNull(
LocalServices.getService(UsageStatsManagerInternal.class));
+ mPendingTasks = new ShortcutPendingTasks(
+ this::injectPostToHandler,
+ this::injectCheckPendingTaskWaitThread,
+ throwable -> wtf(throwable.getMessage(), throwable));
+
if (onlyForPackageManagerApis) {
return; // Don't do anything further. For unit tests only.
}
- mPackageMonitor.register(context, looper, UserHandle.ALL, /* externalStorage= */ false);
-
injectRegisterUidObserver(mUidObserver, ActivityManager.UID_OBSERVER_PROCSTATE
| ActivityManager.UID_OBSERVER_GONE);
}
+ /**
+ * Check whether {@link ShortcutPendingTasks#waitOnAllTasks()} can be called on the current
+ * thread.
+ *
+ * During unit tests, all tasks are executed synchronously which makes the lock held check would
+ * misfire, so we override this method to always return true.
+ */
+ @VisibleForTesting
+ boolean injectCheckPendingTaskWaitThread() {
+ // We shouldn't wait while holding mLock. We should never do this so wtf().
+ if (Thread.holdsLock(mLock)) {
+ wtf("waitOnAllTasks() called while holding the lock");
+ return false;
+ }
+ // This shouldn't be called on the handler thread either.
+ if (Thread.currentThread() == mHandler.getLooper().getThread()) {
+ wtf("waitOnAllTasks() called on handler thread");
+ return false;
+ }
+ return true;
+ }
+
void logDurationStat(int statId, long start) {
synchronized (mStatLock) {
mCountStats[statId]++;
@@ -1492,6 +1516,8 @@ public class ShortcutService extends IShortcutService.Stub {
@UserIdInt int userId) {
verifyCaller(packageName, userId);
+ mPendingTasks.waitOnAllTasks();
+
final List<ShortcutInfo> newShortcuts = (List<ShortcutInfo>) shortcutInfoList.getList();
final int size = newShortcuts.size();
@@ -1541,6 +1567,8 @@ public class ShortcutService extends IShortcutService.Stub {
@UserIdInt int userId) {
verifyCaller(packageName, userId);
+ mPendingTasks.waitOnAllTasks();
+
final List<ShortcutInfo> newShortcuts = (List<ShortcutInfo>) shortcutInfoList.getList();
final int size = newShortcuts.size();
@@ -1619,6 +1647,8 @@ public class ShortcutService extends IShortcutService.Stub {
@UserIdInt int userId) {
verifyCaller(packageName, userId);
+ mPendingTasks.waitOnAllTasks();
+
final List<ShortcutInfo> newShortcuts = (List<ShortcutInfo>) shortcutInfoList.getList();
final int size = newShortcuts.size();
@@ -1669,6 +1699,8 @@ public class ShortcutService extends IShortcutService.Stub {
verifyCaller(packageName, userId);
Preconditions.checkNotNull(shortcutIds, "shortcutIds must be provided");
+ mPendingTasks.waitOnAllTasks();
+
synchronized (mLock) {
final ShortcutPackage ps = getPackageShortcutsLocked(packageName, userId);
@@ -1696,6 +1728,8 @@ public class ShortcutService extends IShortcutService.Stub {
verifyCaller(packageName, userId);
Preconditions.checkNotNull(shortcutIds, "shortcutIds must be provided");
+ mPendingTasks.waitOnAllTasks();
+
synchronized (mLock) {
final ShortcutPackage ps = getPackageShortcutsLocked(packageName, userId);
@@ -1716,6 +1750,8 @@ public class ShortcutService extends IShortcutService.Stub {
verifyCaller(packageName, userId);
Preconditions.checkNotNull(shortcutIds, "shortcutIds must be provided");
+ mPendingTasks.waitOnAllTasks();
+
synchronized (mLock) {
final ShortcutPackage ps = getPackageShortcutsLocked(packageName, userId);
@@ -1738,6 +1774,8 @@ public class ShortcutService extends IShortcutService.Stub {
public void removeAllDynamicShortcuts(String packageName, @UserIdInt int userId) {
verifyCaller(packageName, userId);
+ mPendingTasks.waitOnAllTasks();
+
synchronized (mLock) {
getPackageShortcutsLocked(packageName, userId).deleteAllDynamicShortcuts();
}
@@ -1750,6 +1788,9 @@ public class ShortcutService extends IShortcutService.Stub {
public ParceledListSlice<ShortcutInfo> getDynamicShortcuts(String packageName,
@UserIdInt int userId) {
verifyCaller(packageName, userId);
+
+ mPendingTasks.waitOnAllTasks();
+
synchronized (mLock) {
return getShortcutsWithQueryLocked(
packageName, userId, ShortcutInfo.CLONE_REMOVE_FOR_CREATOR,
@@ -1761,6 +1802,9 @@ public class ShortcutService extends IShortcutService.Stub {
public ParceledListSlice<ShortcutInfo> getManifestShortcuts(String packageName,
@UserIdInt int userId) {
verifyCaller(packageName, userId);
+
+ mPendingTasks.waitOnAllTasks();
+
synchronized (mLock) {
return getShortcutsWithQueryLocked(
packageName, userId, ShortcutInfo.CLONE_REMOVE_FOR_CREATOR,
@@ -1772,6 +1816,9 @@ public class ShortcutService extends IShortcutService.Stub {
public ParceledListSlice<ShortcutInfo> getPinnedShortcuts(String packageName,
@UserIdInt int userId) {
verifyCaller(packageName, userId);
+
+ mPendingTasks.waitOnAllTasks();
+
synchronized (mLock) {
return getShortcutsWithQueryLocked(
packageName, userId, ShortcutInfo.CLONE_REMOVE_FOR_CREATOR,
@@ -1801,6 +1848,8 @@ public class ShortcutService extends IShortcutService.Stub {
public int getRemainingCallCount(String packageName, @UserIdInt int userId) {
verifyCaller(packageName, userId);
+ mPendingTasks.waitOnAllTasks();
+
synchronized (mLock) {
return mMaxUpdatesPerInterval
- getPackageShortcutsLocked(packageName, userId).getApiCallCount();
@@ -1811,6 +1860,8 @@ public class ShortcutService extends IShortcutService.Stub {
public long getRateLimitResetTime(String packageName, @UserIdInt int userId) {
verifyCaller(packageName, userId);
+ mPendingTasks.waitOnAllTasks();
+
synchronized (mLock) {
return getNextResetTimeLocked();
}
@@ -1829,6 +1880,8 @@ public class ShortcutService extends IShortcutService.Stub {
public void reportShortcutUsed(String packageName, String shortcutId, int userId) {
verifyCaller(packageName, userId);
+ mPendingTasks.waitOnAllTasks();
+
Preconditions.checkNotNull(shortcutId);
if (DEBUG) {
@@ -1861,6 +1914,8 @@ public class ShortcutService extends IShortcutService.Stub {
public void resetThrottling() {
enforceSystemOrShell();
+ mPendingTasks.waitOnAllTasks();
+
resetThrottlingInner(getCallingUserId());
}
@@ -1893,6 +1948,9 @@ public class ShortcutService extends IShortcutService.Stub {
if (DEBUG) {
Slog.d(TAG, "onApplicationActive: package=" + packageName + " userid=" + userId);
}
+
+ mPendingTasks.waitOnAllTasks();
+
enforceResetThrottlingPermission();
resetPackageThrottling(packageName, userId);
}
@@ -2055,6 +2113,14 @@ public class ShortcutService extends IShortcutService.Stub {
@Nullable String packageName, @Nullable List<String> shortcutIds,
@Nullable ComponentName componentName,
int queryFlags, int userId) {
+
+ // When this method is called from onShortcutChangedInner() in LauncherApps,
+ // we're on the handler thread. Do not try to wait on tasks. Not waiting for pending
+ // tasks on this specific case should be fine.
+ if (Thread.currentThread() != mHandler.getLooper().getThread()) {
+ mPendingTasks.waitOnAllTasks();
+ }
+
final ArrayList<ShortcutInfo> ret = new ArrayList<>();
final boolean cloneKeyFieldOnly =
((queryFlags & ShortcutQuery.FLAG_GET_KEY_FIELDS_ONLY) != 0);
@@ -2133,6 +2199,8 @@ public class ShortcutService extends IShortcutService.Stub {
Preconditions.checkStringNotEmpty(packageName, "packageName");
Preconditions.checkStringNotEmpty(shortcutId, "shortcutId");
+ mPendingTasks.waitOnAllTasks();
+
synchronized (mLock) {
getLauncherShortcutsLocked(callingPackage, userId, launcherUserId)
.attemptToRestoreIfNeededAndSave();
@@ -2170,6 +2238,8 @@ public class ShortcutService extends IShortcutService.Stub {
Preconditions.checkStringNotEmpty(packageName, "packageName");
Preconditions.checkNotNull(shortcutIds, "shortcutIds");
+ mPendingTasks.waitOnAllTasks();
+
synchronized (mLock) {
final ShortcutLauncher launcher =
getLauncherShortcutsLocked(callingPackage, userId, launcherUserId);
@@ -2190,6 +2260,8 @@ public class ShortcutService extends IShortcutService.Stub {
Preconditions.checkStringNotEmpty(packageName, "packageName can't be empty");
Preconditions.checkStringNotEmpty(shortcutId, "shortcutId can't be empty");
+ mPendingTasks.waitOnAllTasks();
+
synchronized (mLock) {
getLauncherShortcutsLocked(callingPackage, userId, launcherUserId)
.attemptToRestoreIfNeededAndSave();
@@ -2220,6 +2292,8 @@ public class ShortcutService extends IShortcutService.Stub {
Preconditions.checkNotNull(packageName, "packageName");
Preconditions.checkNotNull(shortcutId, "shortcutId");
+ mPendingTasks.waitOnAllTasks();
+
synchronized (mLock) {
getLauncherShortcutsLocked(callingPackage, userId, launcherUserId)
.attemptToRestoreIfNeededAndSave();
@@ -2244,6 +2318,8 @@ public class ShortcutService extends IShortcutService.Stub {
Preconditions.checkNotNull(packageName, "packageName");
Preconditions.checkNotNull(shortcutId, "shortcutId");
+ mPendingTasks.waitOnAllTasks();
+
synchronized (mLock) {
getLauncherShortcutsLocked(callingPackage, userId, launcherUserId)
.attemptToRestoreIfNeededAndSave();
@@ -2304,8 +2380,17 @@ public class ShortcutService extends IShortcutService.Stub {
if (DEBUG) {
Slog.d(TAG, "onSystemLocaleChangedNoLock: " + mLocaleChangeSequenceNumber.get());
}
- injectPostToHandler(() -> handleLocaleChanged());
+ mPendingTasks.addTask(() -> handleLocaleChanged());
+ }
+ }
+
+ @Override
+ public void onPackageBroadcast(Intent intent) {
+ if (DEBUG) {
+ Slog.d(TAG, "onPackageBroadcast");
}
+ mPendingTasks.addTask(() -> ShortcutService.this.onPackageBroadcast(
+ new Intent(intent)));
}
}
@@ -2323,58 +2408,49 @@ public class ShortcutService extends IShortcutService.Stub {
}
}
- /**
- * Package event callbacks.
- */
- @VisibleForTesting
- final PackageMonitor mPackageMonitor = new PackageMonitor() {
-
- private boolean isUserUnlocked() {
- return mUserManager.isUserUnlocked(getChangingUserId());
+ private void onPackageBroadcast(Intent intent) {
+ final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
+ if (userId == UserHandle.USER_NULL) {
+ Slog.w(TAG, "Intent broadcast does not contain user handle: " + intent);
+ return;
}
- @Override
- public void onReceive(Context context, Intent intent) {
- // clearCallingIdentity is not needed normally, but need to do it for the unit test.
- final long token = injectClearCallingIdentity();
- try {
- super.onReceive(context, intent);
- } finally {
- injectRestoreCallingIdentity(token);
+ final String action = intent.getAction();
+
+ if (!mUserManager.isUserUnlocked(userId)) {
+ if (DEBUG) {
+ Slog.d(TAG, "Ignoring package broadcast " + action + " for locked/stopped user "
+ + userId);
}
+ return;
}
- @Override
- public void onPackageAdded(String packageName, int uid) {
- if (!isUserUnlocked()) return;
- handlePackageAdded(packageName, getChangingUserId());
+ final Uri intentUri = intent.getData();
+ final String packageName = (intentUri != null) ? intentUri.getSchemeSpecificPart() : null;
+ if (packageName == null) {
+ Slog.w(TAG, "Intent broadcast does not contain package name: " + intent);
+ return;
}
- @Override
- public void onPackageUpdateFinished(String packageName, int uid) {
- if (!isUserUnlocked()) return;
- handlePackageUpdateFinished(packageName, getChangingUserId());
- }
+ final boolean replacing = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
- @Override
- public void onPackageRemoved(String packageName, int uid) {
- if (!isUserUnlocked()) return;
- handlePackageRemoved(packageName, getChangingUserId());
- }
-
- @Override
- public void onPackageDataCleared(String packageName, int uid) {
- if (!isUserUnlocked()) return;
- handlePackageDataCleared(packageName, getChangingUserId());
- }
+ if (Intent.ACTION_PACKAGE_ADDED.equals(action)) {
+ if (replacing) {
+ handlePackageUpdateFinished(packageName, userId);
+ } else {
+ handlePackageAdded(packageName, userId);
+ }
+ } else if (Intent.ACTION_PACKAGE_REMOVED.equals(action)) {
+ if (!replacing) {
+ handlePackageRemoved(packageName, userId);
+ }
+ } else if (Intent.ACTION_PACKAGE_CHANGED.equals(action)) {
+ handlePackageChanged(packageName, userId);
- @Override
- public boolean onPackageChanged(String packageName, int uid, String[] components) {
- if (!isUserUnlocked()) return false;
- handlePackageChanged(packageName, getChangingUserId());
- return false; // We don't need to receive onSomePackagesChanged(), so just false.
+ } else if (Intent.ACTION_PACKAGE_DATA_CLEARED.equals(action)) {
+ handlePackageDataCleared(packageName, userId);
}
- };
+ }
/**
* Called when a user is unlocked.
@@ -3021,6 +3097,9 @@ public class ShortcutService extends IShortcutService.Stub {
pw.println(Log.getStackTraceString(mLastWtfStacktrace));
}
+ pw.println();
+ mPendingTasks.dump(pw, " ");
+
for (int i = 0; i < mUsers.size(); i++) {
pw.println();
mUsers.valueAt(i).dump(pw, " ");
@@ -3069,6 +3148,8 @@ public class ShortcutService extends IShortcutService.Stub {
enforceShell();
+ mPendingTasks.waitOnAllTasks();
+
final int status = (new MyShellCommand()).exec(this, in, out, err, args, resultReceiver);
resultReceiver.send(status, null);
@@ -3095,10 +3176,6 @@ public class ShortcutService extends IShortcutService.Stub {
case "--user":
if (takeUser) {
mUserId = UserHandle.parseUserArg(getNextArgRequired());
- if (!mUserManager.isUserUnlocked(mUserId)) {
- throw new CommandException(
- "User " + mUserId + " is not running or locked");
- }
break;
}
// fallthrough
@@ -3424,6 +3501,7 @@ public class ShortcutService extends IShortcutService.Stub {
@VisibleForTesting
ShortcutPackage getPackageShortcutForTest(String packageName, int userId) {
+ mPendingTasks.waitOnAllTasks();
synchronized (mLock) {
final ShortcutUser user = mUsers.get(userId);
if (user == null) return null;
@@ -3434,8 +3512,12 @@ public class ShortcutService extends IShortcutService.Stub {
@VisibleForTesting
ShortcutInfo getPackageShortcutForTest(String packageName, String shortcutId, int userId) {
+ mPendingTasks.waitOnAllTasks();
synchronized (mLock) {
- final ShortcutPackage pkg = getPackageShortcutForTest(packageName, userId);
+ final ShortcutUser user = mUsers.get(userId);
+ if (user == null) return null;
+
+ final ShortcutPackage pkg = user.getAllPackagesForTest().get(packageName);
if (pkg == null) return null;
return pkg.findShortcutById(shortcutId);
@@ -3470,4 +3552,12 @@ public class ShortcutService extends IShortcutService.Stub {
forEachLoadedUserLocked(u -> u.forAllPackageItems(ShortcutPackageItem::verifyStates));
}
}
+
+ ShortcutPendingTasks getPendingTasksForTest() {
+ return mPendingTasks;
+ }
+
+ Object getLockForTest() {
+ return mLock;
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
index 1be57bccbdb7..01c19d0ca12b 100644
--- a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
@@ -404,6 +404,11 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase {
// During tests, WTF is fatal.
fail(message + " exception: " + th + "\n" + Log.getStackTraceString(th));
}
+
+ @Override
+ boolean injectCheckPendingTaskWaitThread() {
+ return true;
+ }
}
/** ShortcutManager with injection override methods. */
@@ -848,6 +853,8 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase {
protected void shutdownServices() {
if (mService != null) {
+ mService.getPendingTasksForTest().waitOnAllTasks();
+
// Flush all the unsaved data from the previous instance.
mService.saveDirtyInfo();
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
index 0936e4628361..c7673d17424d 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
@@ -62,6 +62,7 @@ import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
import android.Manifest.permission;
import android.app.ActivityManager;
@@ -1297,8 +1298,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
R.xml.shortcut_3);
updatePackageVersion(CALLING_PACKAGE_1, 1);
- mService.mPackageMonitor.onReceive(getTestContext(),
- genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
+ mInternal.onPackageBroadcast(genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
assertTrue(mManager.setDynamicShortcuts(list(
@@ -1316,8 +1316,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
R.xml.shortcut_2);
updatePackageVersion(CALLING_PACKAGE_1, 1);
- mService.mPackageMonitor.onReceive(getTestContext(),
- genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
+ mInternal.onPackageBroadcast(genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
assertTrue(mManager.setDynamicShortcuts(list(
@@ -2815,7 +2814,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
R.xml.shortcut_2);
updatePackageVersion(CALLING_PACKAGE_1, 1);
- mService.mPackageMonitor.onReceive(getTestContext(),
+ mInternal.onPackageBroadcast(
genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
}).assertCallbackCalledForPackageAndUser(CALLING_PACKAGE_1, HANDLE_USER_0)
.areAllManifest()
@@ -2852,7 +2851,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
R.xml.shortcut_0);
updatePackageVersion(CALLING_PACKAGE_1, 1);
- mService.mPackageMonitor.onReceive(getTestContext(),
+ mInternal.onPackageBroadcast(
genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
assertForLauncherCallback(mLauncherApps, () -> {
@@ -3472,7 +3471,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
R.xml.shortcut_2);
updatePackageVersion(CALLING_PACKAGE_1, 1);
- mService.mPackageMonitor.onReceive(getTestContext(),
+ mInternal.onPackageBroadcast(
genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
@@ -3489,7 +3488,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
R.xml.shortcut_1);
updatePackageVersion(CALLING_PACKAGE_1, 1);
- mService.mPackageMonitor.onReceive(getTestContext(),
+ mInternal.onPackageBroadcast(
genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
@@ -3851,7 +3850,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
R.xml.shortcut_1);
updatePackageVersion(CALLING_PACKAGE_1, 1);
- mService.mPackageMonitor.onReceive(getTestContext(),
+ mInternal.onPackageBroadcast(
genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
assertWith(getCallerShortcuts())
@@ -3891,7 +3890,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_3, USER_10));
uninstallPackage(USER_0, CALLING_PACKAGE_1);
- mService.mPackageMonitor.onReceive(getTestContext(),
+ mInternal.onPackageBroadcast(
genPackageDeleteIntent(CALLING_PACKAGE_1, USER_0));
assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_0));
@@ -3911,7 +3910,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
mRunningUsers.put(USER_10, true);
uninstallPackage(USER_10, CALLING_PACKAGE_2);
- mService.mPackageMonitor.onReceive(getTestContext(),
+ mInternal.onPackageBroadcast(
genPackageDeleteIntent(CALLING_PACKAGE_2, USER_10));
assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_0));
@@ -4002,7 +4001,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_2, USER_10));
assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_3, USER_10));
- mService.mPackageMonitor.onReceive(getTestContext(),
+ mInternal.onPackageBroadcast(
genPackageDataClear(CALLING_PACKAGE_1, USER_0));
assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_0));
@@ -4021,7 +4020,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
mRunningUsers.put(USER_10, true);
- mService.mPackageMonitor.onReceive(getTestContext(),
+ mInternal.onPackageBroadcast(
genPackageDataClear(CALLING_PACKAGE_2, USER_10));
assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_0));
@@ -4048,7 +4047,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
R.xml.shortcut_2);
updatePackageVersion(CALLING_PACKAGE_1, 1);
- mService.mPackageMonitor.onReceive(getTestContext(),
+ mInternal.onPackageBroadcast(
genPackageAddIntent(CALLING_PACKAGE_1, USER_10));
runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
@@ -4069,7 +4068,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
});
// Clear data
- mService.mPackageMonitor.onReceive(getTestContext(),
+ mInternal.onPackageBroadcast(
genPackageDataClear(CALLING_PACKAGE_1, USER_10));
// Only manifest shortcuts will remain, and are no longer pinned.
@@ -4134,9 +4133,9 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
reset(c0);
reset(c10);
- mService.mPackageMonitor.onReceive(getTestContext(),
+ mInternal.onPackageBroadcast(
genPackageUpdateIntent(CALLING_PACKAGE_1, USER_0));
- mService.mPackageMonitor.onReceive(getTestContext(),
+ mInternal.onPackageBroadcast(
genPackageUpdateIntent(CALLING_PACKAGE_1, USER_10));
waitOnMainThread();
@@ -4157,7 +4156,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
updatePackageVersion(CALLING_PACKAGE_1, 1);
// Then send the broadcast, to only user-0.
- mService.mPackageMonitor.onReceive(getTestContext(),
+ mInternal.onPackageBroadcast(
genPackageUpdateIntent(CALLING_PACKAGE_1, USER_0));
waitOnMainThread();
@@ -4222,7 +4221,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
updatePackageVersion(CALLING_PACKAGE_2, 10);
// Then send the broadcast, to only user-0.
- mService.mPackageMonitor.onReceive(getTestContext(),
+ mInternal.onPackageBroadcast(
genPackageUpdateIntent(CALLING_PACKAGE_2, USER_0));
mService.handleUnlockUser(USER_10);
@@ -4246,7 +4245,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
updatePackageVersion(CALLING_PACKAGE_3, 100);
// Then send the broadcast, to only user-0.
- mService.mPackageMonitor.onReceive(getTestContext(),
+ mInternal.onPackageBroadcast(
genPackageUpdateIntent(CALLING_PACKAGE_3, USER_0));
mService.handleUnlockUser(USER_10);
@@ -4328,7 +4327,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
// Update the package.
updatePackageVersion(CALLING_PACKAGE_1, 1);
- mService.mPackageMonitor.onReceive(getTestContext(),
+ mInternal.onPackageBroadcast(
genPackageUpdateIntent(CALLING_PACKAGE_1, USER_0));
runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
@@ -4357,7 +4356,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
mRunningUsers.put(USER_10, true);
updatePackageVersion(CALLING_PACKAGE_1, 1);
- mService.mPackageMonitor.onReceive(getTestContext(),
+ mInternal.onPackageBroadcast(
genPackageAddIntent(CALLING_PACKAGE_1, USER_10));
runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
@@ -4389,7 +4388,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
});
// First, no changes.
- mService.mPackageMonitor.onReceive(getTestContext(),
+ mInternal.onPackageBroadcast(
genPackageChangedIntent(CALLING_PACKAGE_1, USER_10));
runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
@@ -4412,7 +4411,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
// Disable activity 1
mEnabledActivityChecker = (activity, userId) -> !ACTIVITY1.equals(activity);
- mService.mPackageMonitor.onReceive(getTestContext(),
+ mInternal.onPackageBroadcast(
genPackageChangedIntent(CALLING_PACKAGE_1, USER_10));
runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
@@ -4432,7 +4431,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
// Re-enable activity 1.
// Manifest shortcuts will be re-published, but dynamic ones are not.
mEnabledActivityChecker = (activity, userId) -> true;
- mService.mPackageMonitor.onReceive(getTestContext(),
+ mInternal.onPackageBroadcast(
genPackageChangedIntent(CALLING_PACKAGE_1, USER_10));
runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
@@ -4456,7 +4455,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
// Disable activity 2
// Because "ms1-alt" and "s2" are both pinned, they will remain, but disabled.
mEnabledActivityChecker = (activity, userId) -> !ACTIVITY2.equals(activity);
- mService.mPackageMonitor.onReceive(getTestContext(),
+ mInternal.onPackageBroadcast(
genPackageChangedIntent(CALLING_PACKAGE_1, USER_10));
runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
@@ -4519,7 +4518,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
setCaller(LAUNCHER_1, USER_0);
assertForLauncherCallback(mLauncherApps, () -> {
updatePackageVersion(CALLING_PACKAGE_1, 1);
- mService.mPackageMonitor.onReceive(getTestContext(),
+ mInternal.onPackageBroadcast(
genPackageUpdateIntent(CALLING_PACKAGE_1, USER_0));
}).assertCallbackCalledForPackageAndUser(CALLING_PACKAGE_1, HANDLE_USER_0)
// Make sure the launcher gets callbacks.
@@ -5635,7 +5634,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
R.xml.shortcut_1);
updatePackageVersion(CALLING_PACKAGE_1, 1);
- mService.mPackageMonitor.onReceive(getTestContext(),
+ mInternal.onPackageBroadcast(
genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
@@ -5656,7 +5655,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
new ComponentName(CALLING_PACKAGE_2, ShortcutActivity.class.getName()),
R.xml.shortcut_5);
updatePackageVersion(CALLING_PACKAGE_2, 1);
- mService.mPackageMonitor.onReceive(getTestContext(),
+ mInternal.onPackageBroadcast(
genPackageAddIntent(CALLING_PACKAGE_2, USER_0));
runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
@@ -5693,7 +5692,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
new ComponentName(CALLING_PACKAGE_2, ShortcutActivity.class.getName()),
R.xml.shortcut_2);
updatePackageLastUpdateTime(CALLING_PACKAGE_2, 1);
- mService.mPackageMonitor.onReceive(getTestContext(),
+ mInternal.onPackageBroadcast(
genPackageAddIntent(CALLING_PACKAGE_2, USER_0));
runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
@@ -5730,7 +5729,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
mRunningUsers.put(USER_10, false);
mUnlockedUsers.put(USER_10, false);
- mService.mPackageMonitor.onReceive(getTestContext(),
+ mInternal.onPackageBroadcast(
genPackageAddIntent(CALLING_PACKAGE_2, USER_10));
runWithCaller(CALLING_PACKAGE_2, USER_10, () -> {
assertEmpty(mManager.getManifestShortcuts());
@@ -5740,7 +5739,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
// Try again, but the user is locked, so still ignored.
mRunningUsers.put(USER_10, true);
- mService.mPackageMonitor.onReceive(getTestContext(),
+ mInternal.onPackageBroadcast(
genPackageAddIntent(CALLING_PACKAGE_2, USER_10));
runWithCaller(CALLING_PACKAGE_2, USER_10, () -> {
assertEmpty(mManager.getManifestShortcuts());
@@ -5751,7 +5750,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
mUnlockedUsers.put(USER_10, true);
// Send PACKAGE_ADD broadcast to have Package 2 on user-10 publish manifest shortcuts.
- mService.mPackageMonitor.onReceive(getTestContext(),
+ mInternal.onPackageBroadcast(
genPackageAddIntent(CALLING_PACKAGE_2, USER_10));
runWithCaller(CALLING_PACKAGE_2, USER_10, () -> {
@@ -5792,7 +5791,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
R.xml.shortcut_5_reverse);
updatePackageLastUpdateTime(CALLING_PACKAGE_2, 1);
- mService.mPackageMonitor.onReceive(getTestContext(),
+ mInternal.onPackageBroadcast(
genPackageAddIntent(CALLING_PACKAGE_2, USER_0));
runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
@@ -5820,7 +5819,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
new ComponentName(CALLING_PACKAGE_2, ShortcutActivity2.class.getName()),
R.xml.shortcut_0);
updatePackageLastUpdateTime(CALLING_PACKAGE_2, 1);
- mService.mPackageMonitor.onReceive(getTestContext(),
+ mInternal.onPackageBroadcast(
genPackageAddIntent(CALLING_PACKAGE_2, USER_0));
// No manifest shortcuts, and pinned ones are disabled.
@@ -5851,7 +5850,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
R.xml.shortcut_error_1);
updatePackageVersion(CALLING_PACKAGE_1, 1);
- mService.mPackageMonitor.onReceive(getTestContext(),
+ mInternal.onPackageBroadcast(
genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
// Only the valid one is published.
@@ -5866,7 +5865,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
R.xml.shortcut_error_2);
updatePackageVersion(CALLING_PACKAGE_1, 1);
- mService.mPackageMonitor.onReceive(getTestContext(),
+ mInternal.onPackageBroadcast(
genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
// Only the valid one is published.
@@ -5881,7 +5880,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
R.xml.shortcut_error_3);
updatePackageVersion(CALLING_PACKAGE_1, 1);
- mService.mPackageMonitor.onReceive(getTestContext(),
+ mInternal.onPackageBroadcast(
genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
// Only the valid one is published.
@@ -5897,7 +5896,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
R.xml.shortcut_error_4);
updatePackageVersion(CALLING_PACKAGE_1, 1);
- mService.mPackageMonitor.onReceive(getTestContext(),
+ mInternal.onPackageBroadcast(
genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
@@ -5925,7 +5924,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
R.xml.shortcut_5);
updatePackageVersion(CALLING_PACKAGE_1, 1);
- mService.mPackageMonitor.onReceive(getTestContext(),
+ mInternal.onPackageBroadcast(
genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
@@ -5963,7 +5962,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
R.xml.shortcut_error_4);
updatePackageVersion(CALLING_PACKAGE_1, 1);
- mService.mPackageMonitor.onReceive(getTestContext(),
+ mInternal.onPackageBroadcast(
genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
// Make sure 3, 4 and 5 still exist but disabled.
@@ -6011,7 +6010,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
R.xml.shortcut_5);
updatePackageVersion(CALLING_PACKAGE_1, 1);
- mService.mPackageMonitor.onReceive(getTestContext(),
+ mInternal.onPackageBroadcast(
genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
// Only the valid one is published.
@@ -6116,7 +6115,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
R.xml.shortcut_2);
updatePackageVersion(CALLING_PACKAGE_1, 1);
- mService.mPackageMonitor.onReceive(getTestContext(),
+ mInternal.onPackageBroadcast(
genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
@@ -6213,7 +6212,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
R.xml.shortcut_1);
updatePackageVersion(CALLING_PACKAGE_1, 1);
- mService.mPackageMonitor.onReceive(getTestContext(),
+ mInternal.onPackageBroadcast(
genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
// Only the valid one is published.
@@ -6232,7 +6231,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
R.xml.shortcut_1_disable);
updatePackageVersion(CALLING_PACKAGE_1, 1);
- mService.mPackageMonitor.onReceive(getTestContext(),
+ mInternal.onPackageBroadcast(
genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
// Because shortcut 1 wasn't pinned, it'll just go away.
@@ -6253,7 +6252,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
R.xml.shortcut_1);
updatePackageVersion(CALLING_PACKAGE_1, 1);
- mService.mPackageMonitor.onReceive(getTestContext(),
+ mInternal.onPackageBroadcast(
genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
// Only the valid one is published.
@@ -6276,7 +6275,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
R.xml.shortcut_1_disable);
updatePackageVersion(CALLING_PACKAGE_1, 1);
- mService.mPackageMonitor.onReceive(getTestContext(),
+ mInternal.onPackageBroadcast(
genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
// Because shortcut 1 was pinned, it'll still exist as pinned, but disabled.
@@ -6309,7 +6308,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
R.xml.shortcut_2_duplicate);
updatePackageVersion(CALLING_PACKAGE_1, 1);
- mService.mPackageMonitor.onReceive(getTestContext(),
+ mInternal.onPackageBroadcast(
genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
@@ -6339,7 +6338,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
new ComponentName(CALLING_PACKAGE_1, ShortcutActivity2.class.getName()),
R.xml.shortcut_5);
updatePackageVersion(CALLING_PACKAGE_1, 1);
- mService.mPackageMonitor.onReceive(getTestContext(),
+ mInternal.onPackageBroadcast(
genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
@@ -6411,7 +6410,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
R.xml.shortcut_5);
updatePackageVersion(CALLING_PACKAGE_1, 1);
- mService.mPackageMonitor.onReceive(getTestContext(),
+ mInternal.onPackageBroadcast(
genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
@@ -6461,7 +6460,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
R.xml.shortcut_2);
updatePackageVersion(CALLING_PACKAGE_1, 1);
- mService.mPackageMonitor.onReceive(getTestContext(),
+ mInternal.onPackageBroadcast(
genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
runWithCaller(LAUNCHER_1, USER_0, () -> {
@@ -6472,7 +6471,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
R.xml.shortcut_1);
updatePackageVersion(CALLING_PACKAGE_1, 1);
- mService.mPackageMonitor.onReceive(getTestContext(),
+ mInternal.onPackageBroadcast(
genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
@@ -6554,7 +6553,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
R.xml.shortcut_5);
updatePackageVersion(CALLING_PACKAGE_1, 1);
- mService.mPackageMonitor.onReceive(getTestContext(),
+ mInternal.onPackageBroadcast(
genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
@@ -6624,7 +6623,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
R.xml.shortcut_2);
updatePackageVersion(CALLING_PACKAGE_1, 1);
- mService.mPackageMonitor.onReceive(getTestContext(),
+ mInternal.onPackageBroadcast(
genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
assertEquals(2, mManager.getManifestShortcuts().size());
@@ -6750,7 +6749,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
R.xml.shortcut_2);
updatePackageVersion(CALLING_PACKAGE_1, 1);
- mService.mPackageMonitor.onReceive(getTestContext(),
+ mInternal.onPackageBroadcast(
genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
assertEquals(2, mManager.getManifestShortcuts().size());
@@ -6899,7 +6898,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
R.xml.shortcut_1);
updatePackageVersion(CALLING_PACKAGE_1, 1);
- mService.mPackageMonitor.onReceive(getTestContext(),
+ mInternal.onPackageBroadcast(
genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
assertEquals(1, mManager.getManifestShortcuts().size());
@@ -6919,7 +6918,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
new ComponentName(CALLING_PACKAGE_1, ShortcutActivity2.class.getName()),
R.xml.shortcut_1_alt);
updatePackageVersion(CALLING_PACKAGE_1, 1);
- mService.mPackageMonitor.onReceive(getTestContext(),
+ mInternal.onPackageBroadcast(
genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
assertEquals(3, mManager.getManifestShortcuts().size());
@@ -6939,7 +6938,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
new ComponentName(CALLING_PACKAGE_1, ShortcutActivity2.class.getName()),
R.xml.shortcut_5_alt); // manifest has 5, but max is 3, so a2 will have 3.
updatePackageVersion(CALLING_PACKAGE_1, 1);
- mService.mPackageMonitor.onReceive(getTestContext(),
+ mInternal.onPackageBroadcast(
genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
assertEquals(5, mManager.getManifestShortcuts().size());
@@ -6958,7 +6957,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
new ComponentName(CALLING_PACKAGE_1, ShortcutActivity2.class.getName()),
R.xml.shortcut_0);
updatePackageVersion(CALLING_PACKAGE_1, 1);
- mService.mPackageMonitor.onReceive(getTestContext(),
+ mInternal.onPackageBroadcast(
genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
assertEquals(0, mManager.getManifestShortcuts().size());
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest3.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest3.java
index eb4db7a0f4af..fcf7ea2dcfbb 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest3.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest3.java
@@ -66,7 +66,7 @@ public class ShortcutManagerTest3 extends BaseShortcutManagerTest {
private void publishManifestShortcuts(ComponentName activity, int resId) {
addManifestShortcutResource(activity, resId);
updatePackageVersion(CALLING_PACKAGE, 1);
- mService.mPackageMonitor.onReceive(getTestContext(),
+ mInternal.onPackageBroadcast(
genPackageAddIntent(CALLING_PACKAGE, USER_0));
}
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutPendingTasksTest.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutPendingTasksTest.java
new file mode 100644
index 000000000000..bf1ed98983df
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutPendingTasksTest.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2016 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.os.Handler;
+import android.os.Looper;
+import android.test.MoreAsserts;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicReference;
+
+/**
+ * Run with:
+ adb install \
+ -r -g ${ANDROID_PRODUCT_OUT}/data/app/FrameworksServicesTests/FrameworksServicesTests.apk &&
+ adb shell am instrument -e class com.android.server.pm.ShortcutPendingTasksTest \
+ -w com.android.frameworks.servicestests
+ */
+@LargeTest
+public class ShortcutPendingTasksTest extends BaseShortcutManagerTest {
+ public void testAll() {
+ final AtomicReference<Throwable> thrown = new AtomicReference<>();
+
+ final AtomicBoolean threadCheckerResult = new AtomicBoolean(true);
+
+ final Handler handler = new Handler(Looper.getMainLooper());
+
+ final ShortcutPendingTasks tasks = new ShortcutPendingTasks(
+ handler::post,
+ threadCheckerResult::get,
+ thrown::set);
+
+ // No pending tasks, shouldn't block.
+ assertTrue(tasks.waitOnAllTasks());
+
+ final AtomicInteger counter = new AtomicInteger();
+
+ // Run one task.
+ tasks.addTask(() -> {
+ try {
+ Thread.sleep(1000);
+ } catch (InterruptedException ignore) {
+ }
+ counter.incrementAndGet();
+ });
+
+ assertTrue(tasks.waitOnAllTasks());
+ assertNull(thrown.get());
+
+ assertEquals(1, counter.get());
+
+ // Run 3 tasks.
+
+ // We use this ID to make sure only one task can run at the same time.
+ final AtomicInteger currentTaskId = new AtomicInteger();
+
+ tasks.addTask(() -> {
+ currentTaskId.set(1);
+ try {
+ Thread.sleep(500);
+ } catch (InterruptedException ignore) {
+ }
+ counter.incrementAndGet();
+ assertEquals(1, currentTaskId.get());
+ });
+ tasks.addTask(() -> {
+ currentTaskId.set(2);
+ try {
+ Thread.sleep(500);
+ } catch (InterruptedException ignore) {
+ }
+ counter.incrementAndGet();
+ assertEquals(2, currentTaskId.get());
+ });
+ tasks.addTask(() -> {
+ currentTaskId.set(3);
+ try {
+ Thread.sleep(500);
+ } catch (InterruptedException ignore) {
+ }
+ counter.incrementAndGet();
+ assertEquals(3, currentTaskId.get());
+ });
+
+ assertTrue(tasks.waitOnAllTasks());
+ assertNull(thrown.get());
+ assertEquals(4, counter.get());
+
+ // No tasks running, shouldn't block.
+ assertTrue(tasks.waitOnAllTasks());
+ assertNull(thrown.get());
+ assertEquals(4, counter.get());
+
+ // Now the thread checker returns false, so waitOnAllTasks() returns false.
+ threadCheckerResult.set(false);
+ assertFalse(tasks.waitOnAllTasks());
+
+ threadCheckerResult.set(true);
+
+ // Make sure the exception handler is called.
+ tasks.addTask(() -> {
+ throw new RuntimeException("XXX");
+ });
+ assertTrue(tasks.waitOnAllTasks());
+ assertNotNull(thrown.get());
+ MoreAsserts.assertContainsRegex("XXX", thrown.get().getMessage());
+ }
+}