| /* |
| * 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 android.database.sqlite; |
| |
| import android.annotation.TestApi; |
| import android.app.ActivityThread; |
| import android.app.Application; |
| import android.provider.Settings; |
| import android.text.TextUtils; |
| import android.util.KeyValueListParser; |
| import android.util.Log; |
| |
| import com.android.internal.annotations.VisibleForTesting; |
| |
| /** |
| * Helper class for accessing |
| * {@link Settings.Global#SQLITE_COMPATIBILITY_WAL_FLAGS global compatibility WAL settings}. |
| * |
| * <p>The value of {@link Settings.Global#SQLITE_COMPATIBILITY_WAL_FLAGS} is cached on first access |
| * for consistent behavior across all connections opened in the process. |
| * @hide |
| */ |
| @TestApi |
| public class SQLiteCompatibilityWalFlags { |
| |
| private static final String TAG = "SQLiteCompatibilityWalFlags"; |
| |
| private static volatile boolean sInitialized; |
| private static volatile boolean sLegacyCompatibilityWalEnabled; |
| private static volatile String sWALSyncMode; |
| private static volatile long sTruncateSize = -1; |
| // This flag is used to avoid recursive initialization due to circular dependency on Settings |
| private static volatile boolean sCallingGlobalSettings; |
| |
| private SQLiteCompatibilityWalFlags() { |
| } |
| |
| /** |
| * @hide |
| */ |
| @VisibleForTesting |
| public static boolean isLegacyCompatibilityWalEnabled() { |
| initIfNeeded(); |
| return sLegacyCompatibilityWalEnabled; |
| } |
| |
| /** |
| * @hide |
| */ |
| @VisibleForTesting |
| public static String getWALSyncMode() { |
| initIfNeeded(); |
| // The configurable WAL sync mode should only ever be used if the legacy compatibility |
| // WAL is enabled. It should *not* have any effect if app developers explicitly turn on |
| // WAL for their database using setWriteAheadLoggingEnabled. Throwing an exception here |
| // adds an extra layer of checking that we never use it in the wrong place. |
| if (!sLegacyCompatibilityWalEnabled) { |
| throw new IllegalStateException("isLegacyCompatibilityWalEnabled() == false"); |
| } |
| |
| return sWALSyncMode; |
| } |
| |
| /** |
| * Override {@link com.android.internal.R.integer#db_wal_truncate_size}. |
| * |
| * @return the value set in the global setting, or -1 if a value is not set. |
| * |
| * @hide |
| */ |
| @VisibleForTesting |
| public static long getTruncateSize() { |
| initIfNeeded(); |
| return sTruncateSize; |
| } |
| |
| private static void initIfNeeded() { |
| if (sInitialized || sCallingGlobalSettings) { |
| return; |
| } |
| ActivityThread activityThread = ActivityThread.currentActivityThread(); |
| Application app = activityThread == null ? null : activityThread.getApplication(); |
| String flags = null; |
| if (app == null) { |
| Log.w(TAG, "Cannot read global setting " |
| + Settings.Global.SQLITE_COMPATIBILITY_WAL_FLAGS + " - " |
| + "Application state not available"); |
| } else { |
| try { |
| sCallingGlobalSettings = true; |
| flags = Settings.Global.getString(app.getContentResolver(), |
| Settings.Global.SQLITE_COMPATIBILITY_WAL_FLAGS); |
| } finally { |
| sCallingGlobalSettings = false; |
| } |
| } |
| |
| init(flags); |
| } |
| |
| /** |
| * @hide |
| */ |
| @VisibleForTesting |
| public static void init(String flags) { |
| if (TextUtils.isEmpty(flags)) { |
| sInitialized = true; |
| return; |
| } |
| KeyValueListParser parser = new KeyValueListParser(','); |
| try { |
| parser.setString(flags); |
| } catch (IllegalArgumentException e) { |
| Log.e(TAG, "Setting has invalid format: " + flags, e); |
| sInitialized = true; |
| return; |
| } |
| sLegacyCompatibilityWalEnabled = parser.getBoolean( |
| "legacy_compatibility_wal_enabled", false); |
| sWALSyncMode = parser.getString("wal_syncmode", SQLiteGlobal.getWALSyncMode()); |
| sTruncateSize = parser.getInt("truncate_size", -1); |
| Log.i(TAG, "Read compatibility WAL flags: legacy_compatibility_wal_enabled=" |
| + sLegacyCompatibilityWalEnabled + ", wal_syncmode=" + sWALSyncMode); |
| sInitialized = true; |
| } |
| |
| /** |
| * @hide |
| */ |
| @VisibleForTesting |
| @TestApi |
| public static void reset() { |
| sInitialized = false; |
| sLegacyCompatibilityWalEnabled = false; |
| sWALSyncMode = null; |
| } |
| } |