1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.database.sqlite; 18 19 import android.app.ActivityThread; 20 import android.app.Application; 21 import android.provider.Settings; 22 import android.text.TextUtils; 23 import android.util.KeyValueListParser; 24 import android.util.Log; 25 26 import com.android.internal.annotations.VisibleForTesting; 27 28 /** 29 * Helper class for accessing 30 * {@link Settings.Global#SQLITE_COMPATIBILITY_WAL_FLAGS global compatibility WAL settings}. 31 * 32 * <p>The value of {@link Settings.Global#SQLITE_COMPATIBILITY_WAL_FLAGS} is cached on first access 33 * for consistent behavior across all connections opened in the process. 34 * @hide 35 */ 36 public class SQLiteCompatibilityWalFlags { 37 38 private static final String TAG = "SQLiteCompatibilityWalFlags"; 39 40 private static volatile boolean sInitialized; 41 private static volatile boolean sFlagsSet; 42 private static volatile boolean sCompatibilityWalSupported; 43 private static volatile String sWALSyncMode; 44 // This flag is used to avoid recursive initialization due to circular dependency on Settings 45 private static volatile boolean sCallingGlobalSettings; 46 47 /** 48 * @hide 49 */ 50 @VisibleForTesting 51 public static boolean areFlagsSet() { 52 initIfNeeded(); 53 return sFlagsSet; 54 } 55 56 /** 57 * @hide 58 */ 59 @VisibleForTesting 60 public static boolean isCompatibilityWalSupported() { 61 initIfNeeded(); 62 return sCompatibilityWalSupported; 63 } 64 65 /** 66 * @hide 67 */ 68 @VisibleForTesting 69 public static String getWALSyncMode() { 70 initIfNeeded(); 71 return sWALSyncMode; 72 } 73 74 private static void initIfNeeded() { 75 if (sInitialized || sCallingGlobalSettings) { 76 return; 77 } 78 ActivityThread activityThread = ActivityThread.currentActivityThread(); 79 Application app = activityThread == null ? null : activityThread.getApplication(); 80 String flags = null; 81 if (app == null) { 82 Log.w(TAG, "Cannot read global setting " 83 + Settings.Global.SQLITE_COMPATIBILITY_WAL_FLAGS + " - " 84 + "Application state not available"); 85 } else { 86 try { 87 sCallingGlobalSettings = true; 88 flags = Settings.Global.getString(app.getContentResolver(), 89 Settings.Global.SQLITE_COMPATIBILITY_WAL_FLAGS); 90 } finally { 91 sCallingGlobalSettings = false; 92 } 93 } 94 95 init(flags); 96 } 97 98 /** 99 * @hide 100 */ 101 @VisibleForTesting 102 public static void init(String flags) { 103 if (TextUtils.isEmpty(flags)) { 104 sInitialized = true; 105 return; 106 } 107 KeyValueListParser parser = new KeyValueListParser(','); 108 try { 109 parser.setString(flags); 110 } catch (IllegalArgumentException e) { 111 Log.e(TAG, "Setting has invalid format: " + flags, e); 112 sInitialized = true; 113 return; 114 } 115 sCompatibilityWalSupported = parser.getBoolean("compatibility_wal_supported", 116 SQLiteGlobal.isCompatibilityWalSupported()); 117 sWALSyncMode = parser.getString("wal_syncmode", SQLiteGlobal.getWALSyncMode()); 118 Log.i(TAG, "Read compatibility WAL flags: compatibility_wal_supported=" 119 + sCompatibilityWalSupported + ", wal_syncmode=" + sWALSyncMode); 120 sFlagsSet = true; 121 sInitialized = true; 122 } 123 124 /** 125 * @hide 126 */ 127 @VisibleForTesting 128 public static void reset() { 129 sInitialized = false; 130 sFlagsSet = false; 131 sCompatibilityWalSupported = false; 132 sWALSyncMode = null; 133 } 134 } 135