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

Commit eafe89b2 authored by Edgar Arriaga García's avatar Edgar Arriaga García Committed by Android (Google) Code Review
Browse files

Merge changes from topic "database-improvements"

* changes:
  Make slow queries logs show only when log tag enabled
  Remove old and unnecessary log
  Add some tests for database operations
  Add support for normal sync mode and propagate journalMode and syncMode on database open
  Add total execution time and statements executed to dumpsys dbinfo
parents fcb499b8 87e9c5da
Loading
Loading
Loading
Loading
+248 −11
Original line number Diff line number Diff line
@@ -24,19 +24,17 @@ import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.perftests.utils.BenchmarkState;
import android.perftests.utils.PerfStatusReporter;

import androidx.test.InstrumentationRegistry;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;

import java.io.File;
import java.util.Random;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;

import java.util.Random;

/**
 * Performance tests for typical CRUD operations and loading rows into the Cursor
 *
@@ -58,12 +56,9 @@ public class SQLiteDatabasePerfTest {
    public void setUp() {
        mContext = InstrumentationRegistry.getTargetContext();
        mContext.deleteDatabase(DB_NAME);
        mDatabase = mContext.openOrCreateDatabase(DB_NAME, Context.MODE_PRIVATE, null);
        mDatabase.execSQL("CREATE TABLE T1 "
                + "(_ID INTEGER PRIMARY KEY, COL_A INTEGER, COL_B VARCHAR(100), COL_C REAL)");
        mDatabase.execSQL("CREATE TABLE T2 ("
                + "_ID INTEGER PRIMARY KEY, COL_A VARCHAR(100), T1_ID INTEGER,"
                + "FOREIGN KEY(T1_ID) REFERENCES T1 (_ID))");

        createOrOpenTestDatabase(
                SQLiteDatabase.JOURNAL_MODE_TRUNCATE, SQLiteDatabase.SYNC_MODE_FULL);
    }

    @After
@@ -72,6 +67,25 @@ public class SQLiteDatabasePerfTest {
        mContext.deleteDatabase(DB_NAME);
    }

    private void createOrOpenTestDatabase(String journalMode, String syncMode) {
        SQLiteDatabase.OpenParams.Builder paramsBuilder = new SQLiteDatabase.OpenParams.Builder();
        File dbFile = mContext.getDatabasePath(DB_NAME);
        if (journalMode != null) {
            paramsBuilder.setJournalMode(journalMode);
        }
        if (syncMode != null) {
            paramsBuilder.setSynchronousMode(syncMode);
        }
        paramsBuilder.addOpenFlags(SQLiteDatabase.CREATE_IF_NECESSARY);

        mDatabase = SQLiteDatabase.openDatabase(dbFile, paramsBuilder.build());
        mDatabase.execSQL("CREATE TABLE T1 "
                + "(_ID INTEGER PRIMARY KEY, COL_A INTEGER, COL_B VARCHAR(100), COL_C REAL)");
        mDatabase.execSQL("CREATE TABLE T2 ("
                + "_ID INTEGER PRIMARY KEY, COL_A VARCHAR(100), T1_ID INTEGER,"
                + "FOREIGN KEY(T1_ID) REFERENCES T1 (_ID))");
    }

    @Test
    public void testSelect() {
        insertT1TestDataSet();
@@ -192,10 +206,25 @@ public class SQLiteDatabasePerfTest {
        }
    }

    /**
     * This test measures the insertion of a single row into a database using DELETE journal and
     * synchronous modes.
     */
    @Test
    public void testInsert() {
        insertT1TestDataSet();

        testInsertInternal("testInsert");
    }

    @Test
    public void testInsertWithPersistFull() {
        recreateTestDatabase(SQLiteDatabase.JOURNAL_MODE_PERSIST, SQLiteDatabase.SYNC_MODE_FULL);
        insertT1TestDataSet();
        testInsertInternal("testInsertWithPersistFull");
    }

    private void testInsertInternal(String traceTag) {
        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();

        ContentValues cv = new ContentValues();
@@ -203,11 +232,88 @@ public class SQLiteDatabasePerfTest {
        cv.put("COL_B", "NewValue");
        cv.put("COL_C", 1.1);
        String[] deleteArgs = new String[] {String.valueOf(DEFAULT_DATASET_SIZE)};

        while (state.keepRunning()) {
            android.os.Trace.beginSection(traceTag);
            assertEquals(DEFAULT_DATASET_SIZE, mDatabase.insert("T1", null, cv));
            state.pauseTiming();
            assertEquals(1, mDatabase.delete("T1", "_ID=?", deleteArgs));
            state.resumeTiming();
            android.os.Trace.endSection();
        }
    }

    /**
     * This test measures the insertion of a single row into a database using WAL journal mode and
     * NORMAL synchronous mode.
     */
    @Test
    public void testInsertWithWalNormalMode() {
        recreateTestDatabase(SQLiteDatabase.JOURNAL_MODE_WAL, SQLiteDatabase.SYNC_MODE_NORMAL);
        insertT1TestDataSet();

        testInsertInternal("testInsertWithWalNormalMode");
    }

    /**
     * This test measures the insertion of a single row into a database using WAL journal mode and
     * FULL synchronous mode. The goal is to see the difference between NORMAL vs FULL sync modes.
     */
    @Test
    public void testInsertWithWalFullMode() {
        recreateTestDatabase(SQLiteDatabase.JOURNAL_MODE_WAL, SQLiteDatabase.SYNC_MODE_FULL);

        insertT1TestDataSet();

        testInsertInternal("testInsertWithWalFullMode");
    }

    /**
     * This test measures the insertion of a multiple rows in a single transaction using WAL journal
     * mode and NORMAL synchronous mode.
     */
    @Test
    public void testBulkInsertWithWalNormalMode() {
        recreateTestDatabase(SQLiteDatabase.JOURNAL_MODE_WAL, SQLiteDatabase.SYNC_MODE_NORMAL);
        testBulkInsertInternal("testBulkInsertWithWalNormalMode");
    }

    @Test
    public void testBulkInsertWithPersistFull() {
        recreateTestDatabase(SQLiteDatabase.JOURNAL_MODE_PERSIST, SQLiteDatabase.SYNC_MODE_FULL);
        testBulkInsertInternal("testBulkInsertWithPersistFull");
    }

    /**
     * This test measures the insertion of a multiple rows in a single transaction using TRUNCATE
     * journal mode and FULL synchronous mode.
     */
    @Test
    public void testBulkInsert() {
        testBulkInsertInternal("testBulkInsert");
    }

    private void testBulkInsertInternal(String traceTag) {
        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();

        String[] statements = new String[DEFAULT_DATASET_SIZE];
        for (int i = 0; i < DEFAULT_DATASET_SIZE; ++i) {
            statements[i] = "INSERT INTO T1 VALUES (?,?,?,?)";
        }

        while (state.keepRunning()) {
            android.os.Trace.beginSection(traceTag);
            mDatabase.beginTransaction();
            for (int i = 0; i < DEFAULT_DATASET_SIZE; ++i) {
                mDatabase.execSQL(statements[i], new Object[] {i, i, "T1Value" + i, i * 1.1});
            }
            mDatabase.setTransactionSuccessful();
            mDatabase.endTransaction();
            android.os.Trace.endSection();

            state.pauseTiming();
            mDatabase.execSQL("DELETE FROM T1");
            state.resumeTiming();
        }
    }

@@ -227,9 +333,30 @@ public class SQLiteDatabasePerfTest {
        }
    }

    /**
     * This test measures the update of a random row in a database.
     */
    @Test
    public void testUpdateWithWalNormalMode() {
        recreateTestDatabase(SQLiteDatabase.JOURNAL_MODE_WAL, SQLiteDatabase.SYNC_MODE_NORMAL);
        insertT1TestDataSet();
        testUpdateInternal("testUpdateWithWalNormalMode");
    }

    @Test
    public void testUpdateWithPersistFull() {
        recreateTestDatabase(SQLiteDatabase.JOURNAL_MODE_PERSIST, SQLiteDatabase.SYNC_MODE_FULL);
        insertT1TestDataSet();
        testUpdateInternal("testUpdateWithPersistFull");
    }

    @Test
    public void testUpdate() {
        insertT1TestDataSet();
        testUpdateInternal("testUpdate");
    }

    private void testUpdateInternal(String traceTag) {
        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();

        Random rnd = new Random(0);
@@ -237,6 +364,7 @@ public class SQLiteDatabasePerfTest {
        ContentValues cv = new ContentValues();
        String[] argArray = new String[1];
        while (state.keepRunning()) {
            android.os.Trace.beginSection(traceTag);
            int id = rnd.nextInt(DEFAULT_DATASET_SIZE);
            cv.put("COL_A", i);
            cv.put("COL_B", "UpdatedValue");
@@ -244,6 +372,109 @@ public class SQLiteDatabasePerfTest {
            argArray[0] = String.valueOf(id);
            assertEquals(1, mDatabase.update("T1", cv, "_ID=?", argArray));
            i++;
            android.os.Trace.endSection();
        }
    }

    /**
     * This test measures a multi-threaded read-write environment where there are 2 readers and
     * 1 writer in the database using TRUNCATE journal mode and FULL syncMode.
     */
    @Test
    public void testMultithreadedReadWrite() {
        insertT1TestDataSet();
        performMultithreadedReadWriteTest();
    }

    private void doReadLoop(int totalIterations) {
        Random rnd = new Random(0);
        int currentIteration = 0;
        while (currentIteration < totalIterations) {
            android.os.Trace.beginSection("ReadDatabase");
            int index = rnd.nextInt(DEFAULT_DATASET_SIZE);
            try (Cursor cursor = mDatabase.rawQuery("SELECT _ID, COL_A, COL_B, COL_C FROM T1 "
                                 + "WHERE _ID=?",
                         new String[] {String.valueOf(index)})) {
                cursor.moveToNext();
                cursor.getInt(0);
                cursor.getInt(1);
                cursor.getString(2);
                cursor.getDouble(3);
            }
            ++currentIteration;
            android.os.Trace.endSection();
        }
    }

    private void doReadLoop(BenchmarkState state) {
        Random rnd = new Random(0);
        while (state.keepRunning()) {
            android.os.Trace.beginSection("ReadDatabase");
            int index = rnd.nextInt(DEFAULT_DATASET_SIZE);
            try (Cursor cursor = mDatabase.rawQuery("SELECT _ID, COL_A, COL_B, COL_C FROM T1 "
                                 + "WHERE _ID=?",
                         new String[] {String.valueOf(index)})) {
                cursor.moveToNext();
                cursor.getInt(0);
                cursor.getInt(1);
                cursor.getString(2);
                cursor.getDouble(3);
            }
            android.os.Trace.endSection();
        }
    }

    private void doUpdateLoop(int totalIterations) {
        SQLiteDatabase db = mContext.openOrCreateDatabase(DB_NAME, Context.MODE_PRIVATE, null);
        Random rnd = new Random(0);
        int i = 0;
        ContentValues cv = new ContentValues();
        String[] argArray = new String[1];

        while (i < totalIterations) {
            android.os.Trace.beginSection("UpdateDatabase");
            int id = rnd.nextInt(DEFAULT_DATASET_SIZE);
            cv.put("COL_A", i);
            cv.put("COL_B", "UpdatedValue");
            cv.put("COL_C", i);
            argArray[0] = String.valueOf(id);
            db.update("T1", cv, "_ID=?", argArray);
            i++;
            android.os.Trace.endSection();
        }
    }

    /**
     * This test measures a multi-threaded read-write environment where there are 2 readers and
     * 1 writer in the database using WAL journal mode and NORMAL syncMode.
     */
    @Test
    public void testMultithreadedReadWriteWithWalNormal() {
        recreateTestDatabase(SQLiteDatabase.JOURNAL_MODE_WAL, SQLiteDatabase.SYNC_MODE_NORMAL);
        insertT1TestDataSet();

        performMultithreadedReadWriteTest();
    }

    private void performMultithreadedReadWriteTest() {
        int totalBGIterations = 10000;
        // Writer - Fixed iterations to avoid consuming cycles from mainloop benchmark iterations
        Thread updateThread = new Thread(() -> { doUpdateLoop(totalBGIterations); });

        // Reader 1 - Fixed iterations to avoid consuming cycles from mainloop benchmark iterations
        Thread readerThread = new Thread(() -> { doReadLoop(totalBGIterations); });

        updateThread.start();
        readerThread.start();

        // Reader 2
        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
        doReadLoop(state);

        try {
            updateThread.join();
            readerThread.join();
        } catch (Exception e) {
        }
    }

@@ -270,5 +501,11 @@ public class SQLiteDatabasePerfTest {
        mDatabase.setTransactionSuccessful();
        mDatabase.endTransaction();
    }

    private void recreateTestDatabase(String journalMode, String syncMode) {
        mDatabase.close();
        mContext.deleteDatabase(DB_NAME);
        createOrOpenTestDatabase(journalMode, syncMode);
    }
}
+10 −0
Original line number Diff line number Diff line
@@ -14376,11 +14376,21 @@ package android.database.sqlite {
    field public static final int CONFLICT_ROLLBACK = 1; // 0x1
    field public static final int CREATE_IF_NECESSARY = 268435456; // 0x10000000
    field public static final int ENABLE_WRITE_AHEAD_LOGGING = 536870912; // 0x20000000
    field public static final String JOURNAL_MODE_DELETE = "DELETE";
    field public static final String JOURNAL_MODE_MEMORY = "MEMORY";
    field public static final String JOURNAL_MODE_OFF = "OFF";
    field public static final String JOURNAL_MODE_PERSIST = "PERSIST";
    field public static final String JOURNAL_MODE_TRUNCATE = "TRUNCATE";
    field public static final String JOURNAL_MODE_WAL = "WAL";
    field public static final int MAX_SQL_CACHE_SIZE = 100; // 0x64
    field public static final int NO_LOCALIZED_COLLATORS = 16; // 0x10
    field public static final int OPEN_READONLY = 1; // 0x1
    field public static final int OPEN_READWRITE = 0; // 0x0
    field public static final int SQLITE_MAX_LIKE_PATTERN_LENGTH = 50000; // 0xc350
    field public static final String SYNC_MODE_EXTRA = "EXTRA";
    field public static final String SYNC_MODE_FULL = "FULL";
    field public static final String SYNC_MODE_NORMAL = "NORMAL";
    field public static final String SYNC_MODE_OFF = "OFF";
  }
  public static interface SQLiteDatabase.CursorFactory {
+0 −60
Original line number Diff line number Diff line
@@ -143,7 +143,6 @@ public class CursorWindow extends SQLiteClosable implements Parcelable {
            throw new AssertionError(); // Not possible, the native code won't return it.
        }
        mCloseGuard.open("close");
        recordNewWindow(Binder.getCallingPid(), mWindowPtr);
    }

    /**
@@ -191,7 +190,6 @@ public class CursorWindow extends SQLiteClosable implements Parcelable {
            mCloseGuard.close();
        }
        if (mWindowPtr != 0) {
            recordClosingOfWindow(mWindowPtr);
            nativeDispose(mWindowPtr);
            mWindowPtr = 0;
        }
@@ -746,64 +744,6 @@ public class CursorWindow extends SQLiteClosable implements Parcelable {
        dispose();
    }

    @UnsupportedAppUsage
    private static final LongSparseArray<Integer> sWindowToPidMap = new LongSparseArray<Integer>();

    private void recordNewWindow(int pid, long window) {
        synchronized (sWindowToPidMap) {
            sWindowToPidMap.put(window, pid);
            if (Log.isLoggable(STATS_TAG, Log.VERBOSE)) {
                Log.i(STATS_TAG, "Created a new Cursor. " + printStats());
            }
        }
    }

    private void recordClosingOfWindow(long window) {
        synchronized (sWindowToPidMap) {
            if (sWindowToPidMap.size() == 0) {
                // this means we are not in the ContentProvider.
                return;
            }
            sWindowToPidMap.delete(window);
        }
    }

    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
    private String printStats() {
        StringBuilder buff = new StringBuilder();
        int myPid = Process.myPid();
        int total = 0;
        SparseIntArray pidCounts = new SparseIntArray();
        synchronized (sWindowToPidMap) {
            int size = sWindowToPidMap.size();
            if (size == 0) {
                // this means we are not in the ContentProvider.
                return "";
            }
            for (int indx = 0; indx < size; indx++) {
                int pid = sWindowToPidMap.valueAt(indx);
                int value = pidCounts.get(pid);
                pidCounts.put(pid, ++value);
            }
        }
        int numPids = pidCounts.size();
        for (int i = 0; i < numPids;i++) {
            buff.append(" (# cursors opened by ");
            int pid = pidCounts.keyAt(i);
            if (pid == myPid) {
                buff.append("this proc=");
            } else {
                buff.append("pid ").append(pid).append('=');
            }
            int num = pidCounts.get(pid);
            buff.append(num).append(')');
            total += num;
        }
        // limit the returned string size to 1000
        String s = (buff.length() > 980) ? buff.substring(0, 980) : buff.toString();
        return "# Open Cursors=" + total + s;
    }

    private static int getCursorWindowSize() {
        if (sCursorWindowSize < 0) {
            // The cursor window size. resource xml file specifies the value in kB.
+49 −39
Original line number Diff line number Diff line
@@ -26,14 +26,13 @@ import android.os.OperationCanceledException;
import android.os.ParcelFileDescriptor;
import android.os.SystemClock;
import android.os.Trace;
import android.text.TextUtils;
import android.util.Log;
import android.util.LruCache;
import android.util.Pair;
import android.util.Printer;

import dalvik.system.BlockGuard;
import dalvik.system.CloseGuard;

import java.io.File;
import java.io.IOException;
import java.nio.file.FileSystems;
@@ -177,7 +176,7 @@ public final class SQLiteConnection implements CancellationSignal.OnCancelListen
        mConfiguration = new SQLiteDatabaseConfiguration(configuration);
        mConnectionId = connectionId;
        mIsPrimaryConnection = primaryConnection;
        mIsReadOnlyConnection = (configuration.openFlags & SQLiteDatabase.OPEN_READONLY) != 0;
        mIsReadOnlyConnection = mConfiguration.isReadOnlyDatabase();
        mPreparedStatementCache = new PreparedStatementCache(
                mConfiguration.maxSqlCacheSize);
        mCloseGuard.open("close");
@@ -266,7 +265,8 @@ public final class SQLiteConnection implements CancellationSignal.OnCancelListen
        }
        setPageSize();
        setForeignKeyModeFromConfiguration();
        setWalModeFromConfiguration();
        setJournalFromConfiguration();
        setSyncModeFromConfiguration();
        setJournalSizeLimit();
        setAutoCheckpointInterval();
        setLocaleFromConfiguration();
@@ -334,31 +334,20 @@ public final class SQLiteConnection implements CancellationSignal.OnCancelListen
        }
    }

    private void setWalModeFromConfiguration() {
        if (!mConfiguration.isInMemoryDb() && !mIsReadOnlyConnection) {
            final boolean walEnabled =
                    (mConfiguration.openFlags & SQLiteDatabase.ENABLE_WRITE_AHEAD_LOGGING) != 0;
            // Use compatibility WAL unless an app explicitly set journal/synchronous mode
            // or DISABLE_COMPATIBILITY_WAL flag is set
            final boolean isCompatibilityWalEnabled =
                    mConfiguration.isLegacyCompatibilityWalEnabled();
            if (walEnabled || isCompatibilityWalEnabled) {
                setJournalMode("WAL");
                if (mConfiguration.syncMode != null) {
                    setSyncMode(mConfiguration.syncMode);
                } else if (isCompatibilityWalEnabled) {
                    setSyncMode(SQLiteCompatibilityWalFlags.getWALSyncMode());
                } else {
                    setSyncMode(SQLiteGlobal.getWALSyncMode());
                }
    private void setJournalFromConfiguration() {
        if (!mIsReadOnlyConnection) {
            setJournalMode(mConfiguration.resolveJournalMode());
            maybeTruncateWalFile();
        } else {
                setJournalMode(mConfiguration.journalMode == null
                        ? SQLiteGlobal.getDefaultJournalMode() : mConfiguration.journalMode);
                setSyncMode(mConfiguration.syncMode == null
                        ? SQLiteGlobal.getDefaultSyncMode() : mConfiguration.syncMode);
            // No need to truncate for read only databases.
            mConfiguration.shouldTruncateWalFile = false;
        }
    }

    private void setSyncModeFromConfiguration() {
        if (!mIsReadOnlyConnection) {
            setSyncMode(mConfiguration.resolveSyncMode());
        }
    }

    /**
@@ -366,6 +355,10 @@ public final class SQLiteConnection implements CancellationSignal.OnCancelListen
     * PRAGMA wal_checkpoint.
     */
    private void maybeTruncateWalFile() {
        if (!mConfiguration.shouldTruncateWalFile) {
            return;
        }

        final long threshold = SQLiteGlobal.getWALTruncateSize();
        if (DEBUG) {
            Log.d(TAG, "Truncate threshold=" + threshold);
@@ -390,12 +383,17 @@ public final class SQLiteConnection implements CancellationSignal.OnCancelListen
                + threshold + "; truncating");
        try {
            executeForString("PRAGMA wal_checkpoint(TRUNCATE)", null, null);
            mConfiguration.shouldTruncateWalFile = false;
        } catch (SQLiteException e) {
            Log.w(TAG, "Failed to truncate the -wal file", e);
        }
    }

    private void setSyncMode(String newValue) {
    private void setSyncMode(@SQLiteDatabase.SyncMode String newValue) {
        if (TextUtils.isEmpty(newValue)) {
            // No change to the sync mode is intended
            return;
        }
        String value = executeForString("PRAGMA synchronous", null, null);
        if (!canonicalizeSyncMode(value).equalsIgnoreCase(
                canonicalizeSyncMode(newValue))) {
@@ -403,16 +401,21 @@ public final class SQLiteConnection implements CancellationSignal.OnCancelListen
        }
    }

    private static String canonicalizeSyncMode(String value) {
    private static @SQLiteDatabase.SyncMode String canonicalizeSyncMode(String value) {
        switch (value) {
            case "0": return "OFF";
            case "1": return "NORMAL";
            case "2": return "FULL";
            case "0": return SQLiteDatabase.SYNC_MODE_OFF;
            case "1": return SQLiteDatabase.SYNC_MODE_NORMAL;
            case "2": return SQLiteDatabase.SYNC_MODE_FULL;
            case "3": return SQLiteDatabase.SYNC_MODE_EXTRA;
        }
        return value;
    }

    private void setJournalMode(String newValue) {
    private void setJournalMode(@SQLiteDatabase.JournalMode String newValue) {
        if (TextUtils.isEmpty(newValue)) {
            // No change to the journal mode is intended
            return;
        }
        String value = executeForString("PRAGMA journal_mode", null, null);
        if (!value.equalsIgnoreCase(newValue)) {
            try {
@@ -565,9 +568,6 @@ public final class SQLiteConnection implements CancellationSignal.OnCancelListen
        // Remember what changed.
        boolean foreignKeyModeChanged = configuration.foreignKeyConstraintsEnabled
                != mConfiguration.foreignKeyConstraintsEnabled;
        boolean walModeChanged = ((configuration.openFlags ^ mConfiguration.openFlags)
                & (SQLiteDatabase.ENABLE_WRITE_AHEAD_LOGGING
                | SQLiteDatabase.ENABLE_LEGACY_COMPATIBILITY_WAL)) != 0;
        boolean localeChanged = !configuration.locale.equals(mConfiguration.locale);
        boolean customScalarFunctionsChanged = !configuration.customScalarFunctions
                .equals(mConfiguration.customScalarFunctions);
@@ -586,9 +586,19 @@ public final class SQLiteConnection implements CancellationSignal.OnCancelListen
        if (foreignKeyModeChanged) {
            setForeignKeyModeFromConfiguration();
        }
        if (walModeChanged) {
            setWalModeFromConfiguration();

        boolean journalModeChanged = !configuration.resolveJournalMode().equalsIgnoreCase(
                mConfiguration.resolveJournalMode());
        if (journalModeChanged) {
            setJournalFromConfiguration();
        }

        boolean syncModeChanged =
                !configuration.resolveSyncMode().equalsIgnoreCase(mConfiguration.resolveSyncMode());
        if (syncModeChanged) {
            setSyncModeFromConfiguration();
        }

        if (localeChanged) {
            setLocaleFromConfiguration();
        }
+31 −9

File changed.

Preview size limit exceeded, changes collapsed.

Loading