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

Commit c5951997 authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Reduce locking during IO heavy operations." into udc-dev

parents 2942f9a4 88916931
Loading
Loading
Loading
Loading
+115 −98
Original line number Diff line number Diff line
@@ -93,7 +93,6 @@ import android.provider.DeviceConfig;
import android.text.TextUtils;
import android.text.format.TimeMigrationUtils;
import android.util.ArraySet;
import android.util.AtomicFile;
import android.util.KeyValueListParser;
import android.util.Log;
import android.util.Slog;
@@ -149,6 +148,7 @@ import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicLong;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.regex.Pattern;
@@ -321,8 +321,7 @@ public class ShortcutService extends IShortcutService.Stub {
    private final ArrayList<LauncherApps.ShortcutChangeCallback> mShortcutChangeCallbacks =
            new ArrayList<>(1);

    @GuardedBy("mLock")
    private long mRawLastResetTime;
    private final AtomicLong mRawLastResetTime = new AtomicLong(0);

    /**
     * User ID -> UserShortcuts
@@ -756,10 +755,15 @@ public class ShortcutService extends IShortcutService.Stub {
    }

    /** Return the base state file name */
    private AtomicFile getBaseStateFile() {
        final File path = new File(injectSystemDataPath(), FILENAME_BASE_STATE);
        path.mkdirs();
        return new AtomicFile(path);
    final ResilientAtomicFile getBaseStateFile() {
        File mainFile = new File(injectSystemDataPath(), FILENAME_BASE_STATE);
        File temporaryBackup = new File(injectSystemDataPath(),
                FILENAME_BASE_STATE + ".backup");
        File reserveCopy = new File(injectSystemDataPath(),
                FILENAME_BASE_STATE + ".reservecopy");
        int fileMode = FileUtils.S_IRWXU | FileUtils.S_IRWXG | FileUtils.S_IXOTH;
        return new ResilientAtomicFile(mainFile, temporaryBackup, reserveCopy, fileMode,
                "base shortcut", null);
    }

    /**
@@ -976,17 +980,18 @@ public class ShortcutService extends IShortcutService.Stub {
        writeAttr(out, name, intent.toUri(/* flags =*/ 0));
    }

    @GuardedBy("mLock")
    @VisibleForTesting
    void saveBaseStateLocked() {
        final AtomicFile file = getBaseStateFile();
    void saveBaseState() {
        try (ResilientAtomicFile file = getBaseStateFile()) {
            if (DEBUG || DEBUG_REBOOT) {
                Slog.d(TAG, "Saving to " + file.getBaseFile());
            }

            FileOutputStream outs = null;
            try {
                synchronized (mLock) {
                    outs = file.startWrite();
                }

                // Write to XML
                TypedXmlSerializer out = Xml.resolveSerializer(outs);
@@ -994,7 +999,8 @@ public class ShortcutService extends IShortcutService.Stub {
                out.startTag(null, TAG_ROOT);

                // Body.
            writeTagValue(out, TAG_LAST_RESET_TIME, mRawLastResetTime);
                // No locking required. Ok to add lock later if we save more data.
                writeTagValue(out, TAG_LAST_RESET_TIME, mRawLastResetTime.get());

                // Epilogue.
                out.endTag(null, TAG_ROOT);
@@ -1007,16 +1013,23 @@ public class ShortcutService extends IShortcutService.Stub {
                file.failWrite(outs);
            }
        }
    }

    @GuardedBy("mLock")
    private void loadBaseStateLocked() {
        mRawLastResetTime = 0;
        mRawLastResetTime.set(0);

        final AtomicFile file = getBaseStateFile();
        try (ResilientAtomicFile file = getBaseStateFile()) {
            if (DEBUG || DEBUG_REBOOT) {
                Slog.d(TAG, "Loading from " + file.getBaseFile());
            }
        try (FileInputStream in = file.openRead()) {
            FileInputStream in = null;
            try {
                in = file.openRead();
                if (in == null) {
                    throw new FileNotFoundException(file.getBaseFile().getAbsolutePath());
                }

                TypedXmlPullParser parser = Xml.resolvePullParser(in);

                int type;
@@ -1037,7 +1050,7 @@ public class ShortcutService extends IShortcutService.Stub {
                    // Assume depth == 2
                    switch (tag) {
                        case TAG_LAST_RESET_TIME:
                        mRawLastResetTime = parseLongAttribute(parser, ATTR_VALUE);
                            mRawLastResetTime.set(parseLongAttribute(parser, ATTR_VALUE));
                            break;
                        default:
                            Slog.e(TAG, "Invalid tag: " + tag);
@@ -1047,9 +1060,11 @@ public class ShortcutService extends IShortcutService.Stub {
            } catch (FileNotFoundException e) {
                // Use the default
            } catch (IOException | XmlPullParserException e) {
            Slog.e(TAG, "Failed to read file " + file.getBaseFile(), e);

            mRawLastResetTime = 0;
                // Remove corrupted file and retry.
                file.failRead(in, e);
                loadBaseStateLocked();
                return;
            }
        }
        // Adjust the last reset time.
        getLastResetTimeLocked();
@@ -1067,8 +1082,7 @@ public class ShortcutService extends IShortcutService.Stub {
                "user shortcut", null);
    }

    @GuardedBy("mLock")
    private void saveUserLocked(@UserIdInt int userId) {
    private void saveUser(@UserIdInt int userId) {
        try (ResilientAtomicFile file = getUserFile(userId)) {
            FileOutputStream os = null;
            try {
@@ -1076,9 +1090,10 @@ public class ShortcutService extends IShortcutService.Stub {
                    Slog.d(TAG, "Saving to " + file);
                }

                synchronized (mLock) {
                    os = file.startWrite();

                    saveUserInternalLocked(userId, os, /* forBackup= */ false);
                }

                file.finishWrite(os);

@@ -1215,16 +1230,19 @@ public class ShortcutService extends IShortcutService.Stub {
        }
        try {
            Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "shortcutSaveDirtyInfo");
            List<Integer> dirtyUserIds = new ArrayList<>();
            synchronized (mLock) {
                for (int i = mDirtyUserIds.size() - 1; i >= 0; i--) {
                    final int userId = mDirtyUserIds.get(i);
                List<Integer> tmp = mDirtyUserIds;
                mDirtyUserIds = dirtyUserIds;
                dirtyUserIds = tmp;
            }
            for (int i = dirtyUserIds.size() - 1; i >= 0; i--) {
                final int userId = dirtyUserIds.get(i);
                if (userId == UserHandle.USER_NULL) { // USER_NULL for base state.
                        saveBaseStateLocked();
                    saveBaseState();
                } else {
                        saveUserLocked(userId);
                    }
                    saveUser(userId);
                }
                mDirtyUserIds.clear();
            }
        } catch (Exception e) {
            wtf("Exception in saveDirtyInfo", e);
@@ -1237,14 +1255,14 @@ public class ShortcutService extends IShortcutService.Stub {
    @GuardedBy("mLock")
    long getLastResetTimeLocked() {
        updateTimesLocked();
        return mRawLastResetTime;
        return mRawLastResetTime.get();
    }

    /** Return the next reset time. */
    @GuardedBy("mLock")
    long getNextResetTimeLocked() {
        updateTimesLocked();
        return mRawLastResetTime + mResetInterval;
        return mRawLastResetTime.get() + mResetInterval;
    }

    static boolean isClockValid(long time) {
@@ -1259,25 +1277,26 @@ public class ShortcutService extends IShortcutService.Stub {

        final long now = injectCurrentTimeMillis();

        final long prevLastResetTime = mRawLastResetTime;
        final long prevLastResetTime = mRawLastResetTime.get();
        long newLastResetTime = prevLastResetTime;

        if (mRawLastResetTime == 0) { // first launch.
        if (newLastResetTime == 0) { // first launch.
            // TODO Randomize??
            mRawLastResetTime = now;
        } else if (now < mRawLastResetTime) {
            newLastResetTime = now;
        } else if (now < newLastResetTime) {
            // Clock rewound.
            if (isClockValid(now)) {
                Slog.w(TAG, "Clock rewound");
                // TODO Randomize??
                mRawLastResetTime = now;
            }
        } else {
            if ((mRawLastResetTime + mResetInterval) <= now) {
                final long offset = mRawLastResetTime % mResetInterval;
                mRawLastResetTime = ((now / mResetInterval) * mResetInterval) + offset;
                newLastResetTime = now;
            }
        } else if ((newLastResetTime + mResetInterval) <= now) {
            final long offset = newLastResetTime % mResetInterval;
            newLastResetTime = ((now / mResetInterval) * mResetInterval) + offset;
        }
        if (prevLastResetTime != mRawLastResetTime) {

        mRawLastResetTime.set(newLastResetTime);
        if (prevLastResetTime != newLastResetTime) {
            scheduleSaveBaseState();
        }
    }
@@ -2705,9 +2724,7 @@ public class ShortcutService extends IShortcutService.Stub {
    }

    void resetAllThrottlingInner() {
        synchronized (mLock) {
            mRawLastResetTime = injectCurrentTimeMillis();
        }
        mRawLastResetTime.set(injectCurrentTimeMillis());
        scheduleSaveBaseState();
        Slog.i(TAG, "ShortcutManager: throttling counter reset for all users");
    }
@@ -2725,8 +2742,8 @@ public class ShortcutService extends IShortcutService.Stub {
            }
            getPackageShortcutsLocked(packageName, userId)
                    .resetRateLimitingForCommandLineNoSaving();
            saveUserLocked(userId);
        }
        saveUser(userId);
    }

    // We override this method in unit tests to do a simpler check.
@@ -4505,8 +4522,8 @@ public class ShortcutService extends IShortcutService.Stub {
                dumpCurrentTime(pw);
                pw.println();
            });
            saveUserLocked(userId);
        }
        saveUser(userId);
    }

    // === Dump ===
@@ -4717,9 +4734,9 @@ public class ShortcutService extends IShortcutService.Stub {
                pw.print(formatTime(now));

                pw.print("  Raw last reset: [");
                pw.print(mRawLastResetTime);
                pw.print(mRawLastResetTime.get());
                pw.print("] ");
                pw.print(formatTime(mRawLastResetTime));
                pw.print(formatTime(mRawLastResetTime.get()));

                final long last = getLastResetTimeLocked();
                pw.print("  Last reset: [");
+1 −1
Original line number Diff line number Diff line
@@ -201,7 +201,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
        mInjectedCurrentTimeMillis = START_TIME + 4 * INTERVAL + 50;
        assertResetTimes(START_TIME + 4 * INTERVAL, START_TIME + 5 * INTERVAL);

        mService.saveBaseStateLocked();
        mService.saveBaseState();

        dumpBaseStateFile();