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

Commit 42e02e1b authored by Pinyao Ting's avatar Pinyao Ting Committed by Automerger Merge Worker
Browse files

Merge "Use more fine-grained lock when persisting shortcuts to disk" into tm-dev am: 80ed9712

parents e2621d0c 80ed9712
Loading
Loading
Loading
Loading
+10 −0
Original line number Original line Diff line number Diff line
@@ -420,4 +420,14 @@ class ShortcutLauncher extends ShortcutPackageItem {
    ArraySet<String> getAllPinnedShortcutsForTest(String packageName, int packageUserId) {
    ArraySet<String> getAllPinnedShortcutsForTest(String packageName, int packageUserId) {
        return new ArraySet<>(mPinnedShortcuts.get(PackageWithUser.of(packageUserId, packageName)));
        return new ArraySet<>(mPinnedShortcuts.get(PackageWithUser.of(packageUserId, packageName)));
    }
    }

    @Override
    protected File getShortcutPackageItemFile() {
        final File path = new File(mShortcutUser.mService.injectUserDataPath(
                mShortcutUser.getUserId()), ShortcutUser.DIRECTORY_LUANCHERS);
        // Package user id and owner id can have different values for ShortcutLaunchers. Adding
        // user Id to the file name to create a unique path. Owner id is used in the root path.
        final String fileName = getPackageName() + getPackageUserId() + ".xml";
        return new File(path, fileName);
    }
}
}
+20 −18
Original line number Original line Diff line number Diff line
@@ -160,8 +160,6 @@ class ShortcutPackage extends ShortcutPackageItem {
    private static final String KEY_BITMAPS = "bitmaps";
    private static final String KEY_BITMAPS = "bitmaps";
    private static final String KEY_BITMAP_BYTES = "bitmapBytes";
    private static final String KEY_BITMAP_BYTES = "bitmapBytes";


    private final Object mLock = new Object();

    private final Executor mExecutor;
    private final Executor mExecutor;


    /**
    /**
@@ -779,7 +777,7 @@ class ShortcutPackage extends ShortcutPackageItem {
            return false;
            return false;
        }
        }
        mApiCallCount++;
        mApiCallCount++;
        s.scheduleSaveUser(getOwnerUserId());
        scheduleSave();
        return true;
        return true;
    }
    }


@@ -789,7 +787,7 @@ class ShortcutPackage extends ShortcutPackageItem {
        }
        }
        if (mApiCallCount > 0) {
        if (mApiCallCount > 0) {
            mApiCallCount = 0;
            mApiCallCount = 0;
            mShortcutUser.mService.scheduleSaveUser(getOwnerUserId());
            scheduleSave();
        }
        }
    }
    }


@@ -1890,15 +1888,12 @@ class ShortcutPackage extends ShortcutPackageItem {


        final ShortcutPackage ret = new ShortcutPackage(shortcutUser,
        final ShortcutPackage ret = new ShortcutPackage(shortcutUser,
                shortcutUser.getUserId(), packageName);
                shortcutUser.getUserId(), packageName);

        synchronized (ret.mLock) {
        synchronized (ret.mLock) {
            ret.mIsAppSearchSchemaUpToDate = ShortcutService.parseIntAttribute(
            ret.mIsAppSearchSchemaUpToDate = ShortcutService.parseIntAttribute(
                    parser, ATTR_SCHEMA_VERSON, 0) == AppSearchShortcutInfo.SCHEMA_VERSION;
                    parser, ATTR_SCHEMA_VERSON, 0) == AppSearchShortcutInfo.SCHEMA_VERSION;
        }
        }
        ret.mApiCallCount =
        ret.mApiCallCount = ShortcutService.parseIntAttribute(parser, ATTR_CALL_COUNT);
                ShortcutService.parseIntAttribute(parser, ATTR_CALL_COUNT);
        ret.mLastResetTime = ShortcutService.parseLongAttribute(parser, ATTR_LAST_RESET);
        ret.mLastResetTime =
                ShortcutService.parseLongAttribute(parser, ATTR_LAST_RESET);




        final int outerDepth = parser.getDepth();
        final int outerDepth = parser.getDepth();
@@ -2440,9 +2435,9 @@ class ShortcutPackage extends ShortcutPackageItem {
                        })));
                        })));
    }
    }


    void persistsAllShortcutsAsync() {
    @Override
        synchronized (mLock) {
    void scheduleSaveToAppSearchLocked() {
            final Map<String, ShortcutInfo> copy = mShortcuts;
        final Map<String, ShortcutInfo> copy = new ArrayMap<>(mShortcuts);
        if (!mTransientShortcuts.isEmpty()) {
        if (!mTransientShortcuts.isEmpty()) {
            copy.putAll(mTransientShortcuts);
            copy.putAll(mTransientShortcuts);
            mTransientShortcuts.clear();
            mTransientShortcuts.clear();
@@ -2450,7 +2445,6 @@ class ShortcutPackage extends ShortcutPackageItem {
        saveShortcutsAsync(copy.values().stream().filter(ShortcutInfo::usesQuota).collect(
        saveShortcutsAsync(copy.values().stream().filter(ShortcutInfo::usesQuota).collect(
                Collectors.toList()));
                Collectors.toList()));
    }
    }
    }


    private void saveShortcutsAsync(
    private void saveShortcutsAsync(
            @NonNull final Collection<ShortcutInfo> shortcuts) {
            @NonNull final Collection<ShortcutInfo> shortcuts) {
@@ -2548,4 +2542,12 @@ class ShortcutPackage extends ShortcutPackageItem {
            Binder.restoreCallingIdentity(callingIdentity);
            Binder.restoreCallingIdentity(callingIdentity);
        }
        }
    }
    }

    @Override
    protected File getShortcutPackageItemFile() {
        final File path = new File(mShortcutUser.mService.injectUserDataPath(
                mShortcutUser.getUserId()), ShortcutUser.DIRECTORY_PACKAGES);
        final String fileName = getPackageName() + ".xml";
        return new File(path, fileName);
    }
}
}
+45 −4
Original line number Original line Diff line number Diff line
@@ -23,6 +23,7 @@ import android.util.Slog;
import android.util.TypedXmlSerializer;
import android.util.TypedXmlSerializer;
import android.util.Xml;
import android.util.Xml;


import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.Preconditions;
import com.android.internal.util.Preconditions;


import org.json.JSONException;
import org.json.JSONException;
@@ -36,7 +37,7 @@ import java.nio.charset.StandardCharsets;
import java.util.Objects;
import java.util.Objects;


/**
/**
 * All methods should be guarded by {@code #mShortcutUser.mService.mLock}.
 * All methods should be either guarded by {@code #mShortcutUser.mService.mLock} or {@code #mLock}.
 */
 */
abstract class ShortcutPackageItem {
abstract class ShortcutPackageItem {
    private static final String TAG = ShortcutService.TAG;
    private static final String TAG = ShortcutService.TAG;
@@ -49,6 +50,8 @@ abstract class ShortcutPackageItem {


    protected ShortcutUser mShortcutUser;
    protected ShortcutUser mShortcutUser;


    protected final Object mLock = new Object();

    protected ShortcutPackageItem(@NonNull ShortcutUser shortcutUser,
    protected ShortcutPackageItem(@NonNull ShortcutUser shortcutUser,
            int packageUserId, @NonNull String packageName,
            int packageUserId, @NonNull String packageName,
            @NonNull ShortcutPackageInfo packageInfo) {
            @NonNull ShortcutPackageInfo packageInfo) {
@@ -98,7 +101,7 @@ abstract class ShortcutPackageItem {
        }
        }
        final ShortcutService s = mShortcutUser.mService;
        final ShortcutService s = mShortcutUser.mService;
        mPackageInfo.refreshSignature(s, this);
        mPackageInfo.refreshSignature(s, this);
        s.scheduleSaveUser(getOwnerUserId());
        scheduleSave();
    }
    }


    public void attemptToRestoreIfNeededAndSave() {
    public void attemptToRestoreIfNeededAndSave() {
@@ -138,7 +141,7 @@ abstract class ShortcutPackageItem {
        // Either way, it's no longer a shadow.
        // Either way, it's no longer a shadow.
        mPackageInfo.setShadow(false);
        mPackageInfo.setShadow(false);


        s.scheduleSaveUser(mPackageUserId);
        scheduleSave();
    }
    }


    protected abstract boolean canRestoreAnyVersion();
    protected abstract boolean canRestoreAnyVersion();
@@ -148,7 +151,8 @@ abstract class ShortcutPackageItem {
    public abstract void saveToXml(@NonNull TypedXmlSerializer out, boolean forBackup)
    public abstract void saveToXml(@NonNull TypedXmlSerializer out, boolean forBackup)
            throws IOException, XmlPullParserException;
            throws IOException, XmlPullParserException;


    public void saveToFile(File path, boolean forBackup) {
    @GuardedBy("mLock")
    public void saveToFileLocked(File path, boolean forBackup) {
        final AtomicFile file = new AtomicFile(path);
        final AtomicFile file = new AtomicFile(path);
        FileOutputStream os = null;
        FileOutputStream os = null;
        try {
        try {
@@ -176,6 +180,11 @@ abstract class ShortcutPackageItem {
        }
        }
    }
    }


    @GuardedBy("mLock")
    void scheduleSaveToAppSearchLocked() {

    }

    public JSONObject dumpCheckin(boolean clear) throws JSONException {
    public JSONObject dumpCheckin(boolean clear) throws JSONException {
        final JSONObject result = new JSONObject();
        final JSONObject result = new JSONObject();
        result.put(KEY_NAME, mPackageName);
        result.put(KEY_NAME, mPackageName);
@@ -187,4 +196,36 @@ abstract class ShortcutPackageItem {
     */
     */
    public void verifyStates() {
    public void verifyStates() {
    }
    }

    public void scheduleSave() {
        mShortcutUser.mService.injectPostToHandlerDebounced(
                mSaveShortcutPackageRunner, mSaveShortcutPackageRunner);
    }

    private final Runnable mSaveShortcutPackageRunner = this::saveShortcutPackageItem;

    void saveShortcutPackageItem() {
        // Wait for bitmap saves to conclude before proceeding to saving shortcuts.
        mShortcutUser.mService.waitForBitmapSaves();
        // Save each ShortcutPackageItem in a separate Xml file.
        final File path = getShortcutPackageItemFile();
        if (ShortcutService.DEBUG || ShortcutService.DEBUG_REBOOT) {
            Slog.d(TAG, "Saving package item " + getPackageName() + " to " + path);
        }
        synchronized (mLock) {
            path.getParentFile().mkdirs();
            // TODO: Since we are persisting shortcuts into AppSearch, we should read from/write to
            //  AppSearch as opposed to maintaining a separate XML file.
            saveToFileLocked(path, false /*forBackup*/);
            scheduleSaveToAppSearchLocked();
        }
    }

    void removeShortcutPackageItem() {
        synchronized (mLock) {
            getShortcutPackageItemFile().delete();
        }
    }

    protected abstract File getShortcutPackageItemFile();
}
}
+13 −19
Original line number Original line Diff line number Diff line
@@ -748,7 +748,7 @@ public class ShortcutService extends IShortcutService.Stub {
        getUserShortcutsLocked(userId).cancelAllInFlightTasks();
        getUserShortcutsLocked(userId).cancelAllInFlightTasks();


        // Save all dirty information.
        // Save all dirty information.
        saveDirtyInfo(false);
        saveDirtyInfo();


        // Unload
        // Unload
        mUsers.delete(userId);
        mUsers.delete(userId);
@@ -1203,10 +1203,6 @@ public class ShortcutService extends IShortcutService.Stub {


    @VisibleForTesting
    @VisibleForTesting
    void saveDirtyInfo() {
    void saveDirtyInfo() {
        saveDirtyInfo(true);
    }

    private void saveDirtyInfo(boolean saveShortcutsInAppSearch) {
        if (DEBUG || DEBUG_REBOOT) {
        if (DEBUG || DEBUG_REBOOT) {
            Slog.d(TAG, "saveDirtyInfo");
            Slog.d(TAG, "saveDirtyInfo");
        }
        }
@@ -1221,10 +1217,6 @@ public class ShortcutService extends IShortcutService.Stub {
                    if (userId == UserHandle.USER_NULL) { // USER_NULL for base state.
                    if (userId == UserHandle.USER_NULL) { // USER_NULL for base state.
                        saveBaseStateLocked();
                        saveBaseStateLocked();
                    } else {
                    } else {
                        if (saveShortcutsInAppSearch) {
                            getUserShortcutsLocked(userId).forAllPackages(
                                    ShortcutPackage::persistsAllShortcutsAsync);
                        }
                        saveUserLocked(userId);
                        saveUserLocked(userId);
                    }
                    }
                }
                }
@@ -1816,7 +1808,7 @@ public class ShortcutService extends IShortcutService.Stub {
        }
        }
        injectPostToHandlerDebounced(sp, notifyListenerRunnable(packageName, userId));
        injectPostToHandlerDebounced(sp, notifyListenerRunnable(packageName, userId));
        notifyShortcutChangeCallbacks(packageName, userId, changedShortcuts, removedShortcuts);
        notifyShortcutChangeCallbacks(packageName, userId, changedShortcuts, removedShortcuts);
        scheduleSaveUser(userId);
        sp.scheduleSave();
    }
    }


    private void notifyListeners(@NonNull final String packageName, @UserIdInt final int userId) {
    private void notifyListeners(@NonNull final String packageName, @UserIdInt final int userId) {
@@ -2878,13 +2870,12 @@ public class ShortcutService extends IShortcutService.Stub {


        final ShortcutUser user = getUserShortcutsLocked(owningUserId);
        final ShortcutUser user = getUserShortcutsLocked(owningUserId);
        boolean doNotify = false;
        boolean doNotify = false;

        // First, remove the package from the package list (if the package is a publisher).
        // First, remove the package from the package list (if the package is a publisher).
        if (packageUserId == owningUserId) {
        final ShortcutPackage sp = (packageUserId == owningUserId)
            if (user.removePackage(packageName) != null) {
                ? user.removePackage(packageName) : null;
        if (sp != null) {
            doNotify = true;
            doNotify = true;
        }
        }
        }


        // Also remove from the launcher list (if the package is a launcher).
        // Also remove from the launcher list (if the package is a launcher).
        user.removeLauncher(packageUserId, packageName);
        user.removeLauncher(packageUserId, packageName);
@@ -2906,6 +2897,10 @@ public class ShortcutService extends IShortcutService.Stub {
            // notifyListeners.
            // notifyListeners.
            user.rescanPackageIfNeeded(packageName, /* forceRescan=*/ true);
            user.rescanPackageIfNeeded(packageName, /* forceRescan=*/ true);
        }
        }
        if (!appStillExists && (packageUserId == owningUserId) && sp != null) {
            // If the app is removed altogether, we can get rid of the xml as well
            injectPostToHandler(() -> sp.removeShortcutPackageItem());
        }


        if (!wasUserLoaded) {
        if (!wasUserLoaded) {
            // Note this will execute the scheduled save.
            // Note this will execute the scheduled save.
@@ -3788,7 +3783,7 @@ public class ShortcutService extends IShortcutService.Stub {
                if (mHandler.hasCallbacks(mSaveDirtyInfoRunner)) {
                if (mHandler.hasCallbacks(mSaveDirtyInfoRunner)) {
                    mHandler.removeCallbacks(mSaveDirtyInfoRunner);
                    mHandler.removeCallbacks(mSaveDirtyInfoRunner);
                    forEachLoadedUserLocked(ShortcutUser::cancelAllInFlightTasks);
                    forEachLoadedUserLocked(ShortcutUser::cancelAllInFlightTasks);
                    saveDirtyInfo(false);
                    saveDirtyInfo();
                }
                }
                mShutdown.set(true);
                mShutdown.set(true);
            }
            }
@@ -4457,7 +4452,7 @@ public class ShortcutService extends IShortcutService.Stub {


            // Save to the filesystem.
            // Save to the filesystem.
            scheduleSaveUser(userId);
            scheduleSaveUser(userId);
            saveDirtyInfo(false);
            saveDirtyInfo();


            // Note, in case of backup, we don't have to wait on bitmap saving, because we don't
            // Note, in case of backup, we don't have to wait on bitmap saving, because we don't
            // back up bitmaps anyway.
            // back up bitmaps anyway.
@@ -5352,8 +5347,7 @@ public class ShortcutService extends IShortcutService.Stub {
        }
        }
    }
    }


    @VisibleForTesting
    void waitForBitmapSaves() {
    void waitForBitmapSavesForTest() {
        synchronized (mLock) {
        synchronized (mLock) {
            mShortcutBitmapSaver.waitForAllSavesLocked();
            mShortcutBitmapSaver.waitForAllSavesLocked();
        }
        }
+1 −26
Original line number Original line Diff line number Diff line
@@ -407,33 +407,8 @@ class ShortcutUser {
            }
            }
            spi.saveToXml(out, forBackup);
            spi.saveToXml(out, forBackup);
        } else {
        } else {
            // Save each ShortcutPackageItem in a separate Xml file.
            spi.saveShortcutPackageItem();
            final File path = getShortcutPackageItemFile(spi);
            if (ShortcutService.DEBUG || ShortcutService.DEBUG_REBOOT) {
                Slog.d(TAG, "Saving package item " + spi.getPackageName() + " to " + path);
        }
        }

            path.getParentFile().mkdirs();
            spi.saveToFile(path, forBackup);
        }
    }

    private File getShortcutPackageItemFile(ShortcutPackageItem spi) {
        boolean isShortcutLauncher = spi instanceof ShortcutLauncher;

        final File path = new File(mService.injectUserDataPath(mUserId),
                isShortcutLauncher ? DIRECTORY_LUANCHERS : DIRECTORY_PACKAGES);

        final String fileName;
        if (isShortcutLauncher) {
            // Package user id and owner id can have different values for ShortcutLaunchers. Adding
            // user Id to the file name to create a unique path. Owner id is used in the root path.
            fileName = spi.getPackageName() + spi.getPackageUserId() + ".xml";
        } else {
            fileName = spi.getPackageName() + ".xml";
        }

        return new File(path, fileName);
    }
    }


    public static ShortcutUser loadFromXml(ShortcutService s, TypedXmlPullParser parser, int userId,
    public static ShortcutUser loadFromXml(ShortcutService s, TypedXmlPullParser parser, int userId,
Loading