Merge "Broadcast ACTION_SMS_MMS_DB_CREATED when mmssms.db is created."
diff --git a/src/com/android/providers/telephony/MmsSmsDatabaseHelper.java b/src/com/android/providers/telephony/MmsSmsDatabaseHelper.java
index 75885bd..f4ae9cc 100644
--- a/src/com/android/providers/telephony/MmsSmsDatabaseHelper.java
+++ b/src/com/android/providers/telephony/MmsSmsDatabaseHelper.java
@@ -21,11 +21,13 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.SharedPreferences;
 import android.database.Cursor;
 import android.database.sqlite.SQLiteDatabase;
 import android.database.sqlite.SQLiteException;
 import android.database.sqlite.SQLiteOpenHelper;
 import android.os.storage.StorageManager;
+import android.preference.PreferenceManager;
 import android.provider.BaseColumns;
 import android.provider.Telephony;
 import android.provider.Telephony.Mms;
@@ -35,11 +37,14 @@
 import android.provider.Telephony.MmsSms;
 import android.provider.Telephony.MmsSms.PendingMessages;
 import android.provider.Telephony.Sms;
+import android.provider.Telephony.Sms.Intents;
 import android.provider.Telephony.Threads;
 import android.telephony.SubscriptionManager;
 import android.util.Log;
+import android.util.Slog;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.telephony.PhoneFactory;
 import com.google.android.mms.pdu.EncodedStringValue;
 import com.google.android.mms.pdu.PduHeaders;
 
@@ -50,6 +55,7 @@
 import java.util.ArrayList;
 import java.util.HashSet;
 import java.util.Iterator;
+import java.util.concurrent.atomic.AtomicBoolean;
 
 /**
  * A {@link SQLiteOpenHelper} that handles DB management of SMS and MMS tables.
@@ -246,12 +252,22 @@
     private final Context mContext;
     private LowStorageMonitor mLowStorageMonitor;
 
+    // SharedPref key used to check if initial create has been done (if onCreate has already been
+    // called once)
+    private static final String INITIAL_CREATE_DONE = "initial_create_done";
+    // cache for INITIAL_CREATE_DONE shared pref so access to it can be avoided when possible
+    private static AtomicBoolean sInitialCreateDone = new AtomicBoolean(false);
 
     private MmsSmsDatabaseHelper(Context context) {
         super(context, DATABASE_NAME, null, DATABASE_VERSION);
         mContext = context;
         // Memory optimization - close idle connections after 30s of inactivity
         setIdleConnectionTimeout(IDLE_CONNECTION_TIMEOUT_MS);
+        try {
+            PhoneFactory.addLocalLog(TAG, 100);
+        } catch (IllegalArgumentException e) {
+            // ignore
+        }
     }
 
     /**
@@ -463,6 +479,27 @@
 
     @Override
     public void onCreate(SQLiteDatabase db) {
+        localLog("onCreate: Creating all SMS-MMS tables.");
+        // if FBE is not supported, or if this onCreate is for CE partition database
+        if (!StorageManager.isFileEncryptedNativeOrEmulated()
+                || mContext.isCredentialProtectedStorage()) {
+            localLog("onCreate: broadcasting ACTION_SMS_MMS_DB_CREATED");
+            // Broadcast ACTION_SMS_MMS_DB_CREATED
+            Intent intent = new Intent(Sms.Intents.ACTION_SMS_MMS_DB_CREATED);
+            intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
+
+            if (isInitialCreateDone()) {
+                // this onCreate is called after onCreate was called once initially. The db file
+                // disappeared mysteriously?
+                localLogWtf("onCreate: was already called once earlier");
+                intent.putExtra(Intents.EXTRA_IS_INITIAL_CREATE, false);
+            } else {
+                setInitialCreateDone();
+                intent.putExtra(Intents.EXTRA_IS_INITIAL_CREATE, true);
+            }
+
+            mContext.sendBroadcast(intent, android.Manifest.permission.READ_SMS);
+        }
         createMmsTables(db);
         createSmsTables(db);
         createCommonTables(db);
@@ -472,6 +509,30 @@
         createIndices(db);
     }
 
+    private void localLog(String logMsg) {
+        Log.d(TAG, logMsg);
+        PhoneFactory.localLog(TAG, logMsg);
+    }
+
+    private void localLogWtf(String logMsg) {
+        Slog.wtf(TAG, logMsg);
+        PhoneFactory.localLog(TAG, logMsg);
+    }
+
+    private boolean isInitialCreateDone() {
+        SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mContext);
+        return sp.getBoolean(INITIAL_CREATE_DONE, false);
+    }
+
+    private void setInitialCreateDone() {
+        if (!sInitialCreateDone.getAndSet(true)) {
+            SharedPreferences.Editor editor
+                    = PreferenceManager.getDefaultSharedPreferences(mContext).edit();
+            editor.putBoolean(INITIAL_CREATE_DONE, true);
+            editor.commit();
+        }
+    }
+
     // When upgrading the database we need to populate the words
     // table with the rows out of sms and part.
     private void populateWordsTable(SQLiteDatabase db) {
@@ -1526,6 +1587,8 @@
         }
 
         Log.e(TAG, "Destroying all old data.");
+        localLog("onUpgrade: Calling dropAll() and onCreate(). Upgrading database"
+                + " from version " + oldVersion + " to " + currentVersion + "failed.");
         dropAll(db);
         onCreate(db);
     }
@@ -1534,6 +1597,7 @@
         // Clean the database out in order to start over from scratch.
         // We don't need to drop our triggers here because SQLite automatically
         // drops a trigger when its attached database is dropped.
+        localLog("****DROPPING ALL SMS-MMS TABLES****");
         db.execSQL("DROP TABLE IF EXISTS canonical_addresses");
         db.execSQL("DROP TABLE IF EXISTS threads");
         db.execSQL("DROP TABLE IF EXISTS " + MmsSmsProvider.TABLE_PENDING_MSG);
@@ -1825,19 +1889,41 @@
     }
 
     @Override
+    public synchronized  SQLiteDatabase getReadableDatabase() {
+        SQLiteDatabase db = super.getWritableDatabase();
+
+        // getReadableDatabase gets or creates a database. So we know for sure that a database has
+        // already been created at this point.
+        if (mContext.isCredentialProtectedStorage()) {
+            setInitialCreateDone();
+        }
+
+        return db;
+    }
+
+    @Override
     public synchronized SQLiteDatabase getWritableDatabase() {
         SQLiteDatabase db = super.getWritableDatabase();
 
+        // getWritableDatabase gets or creates a database. So we know for sure that a database has
+        // already been created at this point.
+        if (mContext.isCredentialProtectedStorage()) {
+            setInitialCreateDone();
+        }
+
         if (!sTriedAutoIncrement) {
             sTriedAutoIncrement = true;
             boolean hasAutoIncrementThreads = hasAutoIncrement(db, MmsSmsProvider.TABLE_THREADS);
             boolean hasAutoIncrementAddresses = hasAutoIncrement(db, "canonical_addresses");
             boolean hasAutoIncrementPart = hasAutoIncrement(db, "part");
             boolean hasAutoIncrementPdu = hasAutoIncrement(db, "pdu");
-            Log.d(TAG, "[getWritableDatabase] hasAutoIncrementThreads: " + hasAutoIncrementThreads +
+            String logMsg = "[getWritableDatabase]" +
+                    " hasAutoIncrementThreads: " + hasAutoIncrementThreads +
                     " hasAutoIncrementAddresses: " + hasAutoIncrementAddresses +
                     " hasAutoIncrementPart: " + hasAutoIncrementPart +
-                    " hasAutoIncrementPdu: " + hasAutoIncrementPdu);
+                    " hasAutoIncrementPdu: " + hasAutoIncrementPdu;
+            Log.d(TAG, logMsg);
+            localLog(logMsg);
             boolean autoIncrementThreadsSuccess = true;
             boolean autoIncrementAddressesSuccess = true;
             boolean autoIncrementPartSuccess = true;