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

Commit 708703bf authored by Makoto Onuki's avatar Makoto Onuki
Browse files

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
parent 454c831d
Loading
Loading
Loading
Loading
+98 −0
Original line number Diff line number Diff line
/*
 * 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<String, String> mHostPackages = new ArrayMap<>();

    /**
     * Set of package name values from above.
     */
    private final ArraySet<String> 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();
            }
        }
    }
}
+29 −5
Original line number Diff line number Diff line
@@ -279,6 +279,13 @@ public class ShortcutService extends IShortcutService.Stub {
    @GuardedBy("mLock")
    private final SparseArray<ShortcutUser> mUsers = new SparseArray<>();

    /**
     * User ID -> ShortcutNonPersistentUser
     */
    @GuardedBy("mLock")
    private final SparseArray<ShortcutNonPersistentUser> mShortcutNonPersistentUsers =
            new SparseArray<>();

    /**
     * Max number of dynamic + manifest shortcuts that each application can have at a time.
     */
@@ -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<ShortcutUser> 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();
                }
            }
        }
    }

+0 −43
Original line number Diff line number Diff line
@@ -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<String, String> mHostPackages = new ArrayMap<>();

    /**
     * Set of package name values from above.
     */
    private final ArraySet<String> 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++) {