Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit fcf7db9e authored by Makoto Onuki's avatar Makoto Onuki Committed by android-build-merger
Browse files

Merge \"Handle package broadcasts before apps do\" into nyc-mr1-dev

am: ae13eee9

Change-Id: I4eee7d585bfe1218fae425f2b3f2097965924587
parents 66ea62ec ae13eee9
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -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);
}
+8 −0
Original line number Diff line number Diff line
@@ -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;
@@ -11443,6 +11444,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);
@@ -11467,6 +11471,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);
+159 −0
Original line number Diff line number Diff line
/*
 * 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));
    }
}
+169 −32
Original line number Diff line number Diff line
@@ -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
@@ -355,6 +354,12 @@ public class ShortcutService extends IShortcutService.Stub {
    @interface ShortcutOperation {
    }

    @GuardedBy("mLock")
    private int mWtfCount = 0;

    @GuardedBy("mLock")
    private Exception mLastWtfStacktrace;

    public ShortcutService(Context context) {
        this(context, BackgroundThread.get().getLooper(), /*onyForPackgeManagerApis*/ false);
    }
@@ -371,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]++;
@@ -1486,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();

@@ -1535,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();

@@ -1613,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();

@@ -1663,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);

@@ -1690,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);

@@ -1710,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);

@@ -1732,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();
        }
@@ -1744,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,
@@ -1755,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,
@@ -1766,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,
@@ -1795,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();
@@ -1805,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();
        }
@@ -1823,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) {
@@ -1855,6 +1914,8 @@ public class ShortcutService extends IShortcutService.Stub {
    public void resetThrottling() {
        enforceSystemOrShell();

        mPendingTasks.waitOnAllTasks();

        resetThrottlingInner(getCallingUserId());
    }

@@ -1887,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);
    }
@@ -2049,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);
@@ -2127,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();
@@ -2164,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);
@@ -2184,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();
@@ -2213,6 +2291,8 @@ public class ShortcutService extends IShortcutService.Stub {
            Preconditions.checkNotNull(packageName, "packageName");
            Preconditions.checkNotNull(shortcutId, "shortcutId");

            mPendingTasks.waitOnAllTasks();

            synchronized (mLock) {
                getLauncherShortcutsLocked(callingPackage, userId, launcherUserId)
                        .attemptToRestoreIfNeededAndSave();
@@ -2237,6 +2317,8 @@ public class ShortcutService extends IShortcutService.Stub {
            Preconditions.checkNotNull(packageName, "packageName");
            Preconditions.checkNotNull(shortcutId, "shortcutId");

            mPendingTasks.waitOnAllTasks();

            synchronized (mLock) {
                getLauncherShortcutsLocked(callingPackage, userId, launcherUserId)
                        .attemptToRestoreIfNeededAndSave();
@@ -2297,8 +2379,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)));
        }
    }

@@ -2316,37 +2407,49 @@ public class ShortcutService extends IShortcutService.Stub {
        }
    }

    /**
     * Package event callbacks.
     */
    @VisibleForTesting
    final PackageMonitor mPackageMonitor = new PackageMonitor() {
        @Override
        public void onPackageAdded(String packageName, int uid) {
            handlePackageAdded(packageName, 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 onPackageUpdateFinished(String packageName, int uid) {
            handlePackageUpdateFinished(packageName, getChangingUserId());
        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 onPackageRemoved(String packageName, int uid) {
            handlePackageRemoved(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 onPackageDataCleared(String packageName, int uid) {
            handlePackageDataCleared(packageName, getChangingUserId());
        final boolean replacing = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);

        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) {
            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.
@@ -2984,6 +3087,18 @@ public class ShortcutService extends IShortcutService.Stub {
                dumpStatLS(pw, p, Stats.IS_ACTIVITY_ENABLED, "isActivityEnabled");
            }

            pw.println();
            pw.print("  #Failures: ");
            pw.println(mWtfCount);

            if (mLastWtfStacktrace != null) {
                pw.print("  Last failure stack trace: ");
                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, "  ");
@@ -3032,6 +3147,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);
@@ -3303,7 +3420,14 @@ public class ShortcutService extends IShortcutService.Stub {
    }

    // Injection point.
    void wtf(String message, Exception e) {
    void wtf(String message, Throwable e) {
        if (e == null) {
            e = new RuntimeException("Stacktrace");
        }
        synchronized (mLock) {
            mWtfCount++;
            mLastWtfStacktrace = new Exception("Last failure was logged here:");
        }
        Slog.wtf(TAG, message, e);
    }

@@ -3376,6 +3500,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;
@@ -3386,8 +3511,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);
@@ -3422,4 +3551,12 @@ public class ShortcutService extends IShortcutService.Stub {
            forEachLoadedUserLocked(u -> u.forAllPackageItems(ShortcutPackageItem::verifyStates));
        }
    }

    ShortcutPendingTasks getPendingTasksForTest() {
        return mPendingTasks;
    }

    Object getLockForTest() {
        return mLock;
    }
}
+70 −39

File changed.

Preview size limit exceeded, changes collapsed.

Loading