1bd086f1963f13d13a03928f41b9b7979bebffa26Robert Berry/*
2bd086f1963f13d13a03928f41b9b7979bebffa26Robert Berry * Copyright (C) 2017 The Android Open Source Project
3bd086f1963f13d13a03928f41b9b7979bebffa26Robert Berry *
4bd086f1963f13d13a03928f41b9b7979bebffa26Robert Berry * Licensed under the Apache License, Version 2.0 (the "License");
5bd086f1963f13d13a03928f41b9b7979bebffa26Robert Berry * you may not use this file except in compliance with the License.
6bd086f1963f13d13a03928f41b9b7979bebffa26Robert Berry * You may obtain a copy of the License at
7bd086f1963f13d13a03928f41b9b7979bebffa26Robert Berry *
8bd086f1963f13d13a03928f41b9b7979bebffa26Robert Berry *      http://www.apache.org/licenses/LICENSE-2.0
9bd086f1963f13d13a03928f41b9b7979bebffa26Robert Berry *
10bd086f1963f13d13a03928f41b9b7979bebffa26Robert Berry * Unless required by applicable law or agreed to in writing, software
11bd086f1963f13d13a03928f41b9b7979bebffa26Robert Berry * distributed under the License is distributed on an "AS IS" BASIS,
12bd086f1963f13d13a03928f41b9b7979bebffa26Robert Berry * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13bd086f1963f13d13a03928f41b9b7979bebffa26Robert Berry * See the License for the specific language governing permissions and
14bd086f1963f13d13a03928f41b9b7979bebffa26Robert Berry * limitations under the License.
15bd086f1963f13d13a03928f41b9b7979bebffa26Robert Berry */
16bd086f1963f13d13a03928f41b9b7979bebffa26Robert Berry
1776cf0831e030e42ffc0ffa24abd58350eea046e9Robert Berrypackage com.android.server.locksettings.recoverablekeystore.storage;
1876cf0831e030e42ffc0ffa24abd58350eea046e9Robert Berry
1976cf0831e030e42ffc0ffa24abd58350eea046e9Robert Berryimport android.content.Context;
2076cf0831e030e42ffc0ffa24abd58350eea046e9Robert Berryimport android.database.sqlite.SQLiteDatabase;
2176cf0831e030e42ffc0ffa24abd58350eea046e9Robert Berryimport android.database.sqlite.SQLiteOpenHelper;
2214d993dc2c0bbdee6a6ae0c270a92107c9f57a84Bo Zhuimport android.util.Log;
2376cf0831e030e42ffc0ffa24abd58350eea046e9Robert Berry
2476cf0831e030e42ffc0ffa24abd58350eea046e9Robert Berryimport com.android.server.locksettings.recoverablekeystore.storage.RecoverableKeyStoreDbContract.KeysEntry;
25584b923fb7d92a735209ec30b2c5e7d4b8e673ebBo Zhuimport com.android.server.locksettings.recoverablekeystore.storage.RecoverableKeyStoreDbContract.RecoveryServiceMetadataEntry;
26f34fc7e18c2a2ec5cff0bd9d96397311745fbef4Dmitry Dementyevimport com.android.server.locksettings.recoverablekeystore.storage.RecoverableKeyStoreDbContract.RootOfTrustEntry;
27bc08840440d5121035244d8fd45a857becf3b7bbRobert Berryimport com.android.server.locksettings.recoverablekeystore.storage.RecoverableKeyStoreDbContract.UserMetadataEntry;
2876cf0831e030e42ffc0ffa24abd58350eea046e9Robert Berry
2976cf0831e030e42ffc0ffa24abd58350eea046e9Robert Berry/**
3076cf0831e030e42ffc0ffa24abd58350eea046e9Robert Berry * Helper for creating the recoverable key database.
3176cf0831e030e42ffc0ffa24abd58350eea046e9Robert Berry */
3276cf0831e030e42ffc0ffa24abd58350eea046e9Robert Berryclass RecoverableKeyStoreDbHelper extends SQLiteOpenHelper {
3314d993dc2c0bbdee6a6ae0c270a92107c9f57a84Bo Zhu    private static final String TAG = "RecoverableKeyStoreDbHp";
3414d993dc2c0bbdee6a6ae0c270a92107c9f57a84Bo Zhu
35f34fc7e18c2a2ec5cff0bd9d96397311745fbef4Dmitry Dementyev    static final int DATABASE_VERSION = 4;
3676cf0831e030e42ffc0ffa24abd58350eea046e9Robert Berry    private static final String DATABASE_NAME = "recoverablekeystore.db";
3776cf0831e030e42ffc0ffa24abd58350eea046e9Robert Berry
38bc08840440d5121035244d8fd45a857becf3b7bbRobert Berry    private static final String SQL_CREATE_KEYS_ENTRY =
3976cf0831e030e42ffc0ffa24abd58350eea046e9Robert Berry            "CREATE TABLE " + KeysEntry.TABLE_NAME + "( "
4076cf0831e030e42ffc0ffa24abd58350eea046e9Robert Berry                    + KeysEntry._ID + " INTEGER PRIMARY KEY,"
41b7c06ea06a7d18d02becb100958d47c9d96369b5Robert Berry                    + KeysEntry.COLUMN_NAME_USER_ID + " INTEGER,"
42bc08840440d5121035244d8fd45a857becf3b7bbRobert Berry                    + KeysEntry.COLUMN_NAME_UID + " INTEGER,"
43bc08840440d5121035244d8fd45a857becf3b7bbRobert Berry                    + KeysEntry.COLUMN_NAME_ALIAS + " TEXT,"
4476cf0831e030e42ffc0ffa24abd58350eea046e9Robert Berry                    + KeysEntry.COLUMN_NAME_NONCE + " BLOB,"
4576cf0831e030e42ffc0ffa24abd58350eea046e9Robert Berry                    + KeysEntry.COLUMN_NAME_WRAPPED_KEY + " BLOB,"
4676cf0831e030e42ffc0ffa24abd58350eea046e9Robert Berry                    + KeysEntry.COLUMN_NAME_GENERATION_ID + " INTEGER,"
47bc08840440d5121035244d8fd45a857becf3b7bbRobert Berry                    + KeysEntry.COLUMN_NAME_LAST_SYNCED_AT + " INTEGER,"
48ad88471920085d87f377f4e00330f5f25e3ead80Dmitry Dementyev                    + KeysEntry.COLUMN_NAME_RECOVERY_STATUS + " INTEGER,"
49bc08840440d5121035244d8fd45a857becf3b7bbRobert Berry                    + "UNIQUE(" + KeysEntry.COLUMN_NAME_UID + ","
50bc08840440d5121035244d8fd45a857becf3b7bbRobert Berry                    + KeysEntry.COLUMN_NAME_ALIAS + "))";
5176cf0831e030e42ffc0ffa24abd58350eea046e9Robert Berry
52bc08840440d5121035244d8fd45a857becf3b7bbRobert Berry    private static final String SQL_CREATE_USER_METADATA_ENTRY =
53bc08840440d5121035244d8fd45a857becf3b7bbRobert Berry            "CREATE TABLE " + UserMetadataEntry.TABLE_NAME + "( "
54bc08840440d5121035244d8fd45a857becf3b7bbRobert Berry                    + UserMetadataEntry._ID + " INTEGER PRIMARY KEY,"
55bc08840440d5121035244d8fd45a857becf3b7bbRobert Berry                    + UserMetadataEntry.COLUMN_NAME_USER_ID + " INTEGER UNIQUE,"
56bc08840440d5121035244d8fd45a857becf3b7bbRobert Berry                    + UserMetadataEntry.COLUMN_NAME_PLATFORM_KEY_GENERATION_ID + " INTEGER)";
57bc08840440d5121035244d8fd45a857becf3b7bbRobert Berry
5877183effbf21cbaa9dd81b31ba5c0e1a580619a3Dmitry Dementyev    private static final String SQL_CREATE_RECOVERY_SERVICE_METADATA_ENTRY =
59584b923fb7d92a735209ec30b2c5e7d4b8e673ebBo Zhu            "CREATE TABLE " + RecoveryServiceMetadataEntry.TABLE_NAME + " ("
60584b923fb7d92a735209ec30b2c5e7d4b8e673ebBo Zhu                    + RecoveryServiceMetadataEntry._ID + " INTEGER PRIMARY KEY,"
61584b923fb7d92a735209ec30b2c5e7d4b8e673ebBo Zhu                    + RecoveryServiceMetadataEntry.COLUMN_NAME_USER_ID + " INTEGER,"
62584b923fb7d92a735209ec30b2c5e7d4b8e673ebBo Zhu                    + RecoveryServiceMetadataEntry.COLUMN_NAME_UID + " INTEGER,"
6377183effbf21cbaa9dd81b31ba5c0e1a580619a3Dmitry Dementyev                    + RecoveryServiceMetadataEntry.COLUMN_NAME_SNAPSHOT_VERSION + " INTEGER,"
6477183effbf21cbaa9dd81b31ba5c0e1a580619a3Dmitry Dementyev                    + RecoveryServiceMetadataEntry.COLUMN_NAME_SHOULD_CREATE_SNAPSHOT + " INTEGER,"
65f34fc7e18c2a2ec5cff0bd9d96397311745fbef4Dmitry Dementyev                    + RecoveryServiceMetadataEntry.COLUMN_NAME_ACTIVE_ROOT_OF_TRUST + " TEXT,"
66584b923fb7d92a735209ec30b2c5e7d4b8e673ebBo Zhu                    + RecoveryServiceMetadataEntry.COLUMN_NAME_PUBLIC_KEY + " BLOB,"
6714d993dc2c0bbdee6a6ae0c270a92107c9f57a84Bo Zhu                    + RecoveryServiceMetadataEntry.COLUMN_NAME_CERT_PATH + " BLOB,"
6814d993dc2c0bbdee6a6ae0c270a92107c9f57a84Bo Zhu                    + RecoveryServiceMetadataEntry.COLUMN_NAME_CERT_SERIAL + " INTEGER,"
69bdfdf53d08618ed34358b6ba66e1893bd35a4623Dmitry Dementyev                    + RecoveryServiceMetadataEntry.COLUMN_NAME_SECRET_TYPES + " TEXT,"
7077183effbf21cbaa9dd81b31ba5c0e1a580619a3Dmitry Dementyev                    + RecoveryServiceMetadataEntry.COLUMN_NAME_COUNTER_ID + " INTEGER,"
717d8c78a2c88a4898a63b918ab8b974aecd7b165bDmitry Dementyev                    + RecoveryServiceMetadataEntry.COLUMN_NAME_SERVER_PARAMS + " BLOB,"
725b81fa66e8efc2b8ed54973a5f1b1bbd6d7a7b3eBo Zhu                    + "UNIQUE("
73584b923fb7d92a735209ec30b2c5e7d4b8e673ebBo Zhu                    + RecoveryServiceMetadataEntry.COLUMN_NAME_USER_ID  + ","
74584b923fb7d92a735209ec30b2c5e7d4b8e673ebBo Zhu                    + RecoveryServiceMetadataEntry.COLUMN_NAME_UID + "))";
755b81fa66e8efc2b8ed54973a5f1b1bbd6d7a7b3eBo Zhu
76f34fc7e18c2a2ec5cff0bd9d96397311745fbef4Dmitry Dementyev    private static final String SQL_CREATE_ROOT_OF_TRUST_ENTRY =
77f34fc7e18c2a2ec5cff0bd9d96397311745fbef4Dmitry Dementyev            "CREATE TABLE " + RootOfTrustEntry.TABLE_NAME + " ("
78f34fc7e18c2a2ec5cff0bd9d96397311745fbef4Dmitry Dementyev                    + RootOfTrustEntry._ID + " INTEGER PRIMARY KEY,"
79f34fc7e18c2a2ec5cff0bd9d96397311745fbef4Dmitry Dementyev                    + RootOfTrustEntry.COLUMN_NAME_USER_ID + " INTEGER,"
80f34fc7e18c2a2ec5cff0bd9d96397311745fbef4Dmitry Dementyev                    + RootOfTrustEntry.COLUMN_NAME_UID + " INTEGER,"
81f34fc7e18c2a2ec5cff0bd9d96397311745fbef4Dmitry Dementyev                    + RootOfTrustEntry.COLUMN_NAME_ROOT_ALIAS + " TEST,"
82f34fc7e18c2a2ec5cff0bd9d96397311745fbef4Dmitry Dementyev                    + RootOfTrustEntry.COLUMN_NAME_CERT_PATH + " BLOB,"
83f34fc7e18c2a2ec5cff0bd9d96397311745fbef4Dmitry Dementyev                    + RootOfTrustEntry.COLUMN_NAME_CERT_SERIAL + " INTEGER,"
84f34fc7e18c2a2ec5cff0bd9d96397311745fbef4Dmitry Dementyev                    + "UNIQUE("
85f34fc7e18c2a2ec5cff0bd9d96397311745fbef4Dmitry Dementyev                    + RootOfTrustEntry.COLUMN_NAME_USER_ID  + ","
86f34fc7e18c2a2ec5cff0bd9d96397311745fbef4Dmitry Dementyev                    + RootOfTrustEntry.COLUMN_NAME_UID  + ","
87f34fc7e18c2a2ec5cff0bd9d96397311745fbef4Dmitry Dementyev                    + RootOfTrustEntry.COLUMN_NAME_ROOT_ALIAS + "))";
88f34fc7e18c2a2ec5cff0bd9d96397311745fbef4Dmitry Dementyev
89bc08840440d5121035244d8fd45a857becf3b7bbRobert Berry    private static final String SQL_DELETE_KEYS_ENTRY =
9076cf0831e030e42ffc0ffa24abd58350eea046e9Robert Berry            "DROP TABLE IF EXISTS " + KeysEntry.TABLE_NAME;
9176cf0831e030e42ffc0ffa24abd58350eea046e9Robert Berry
92bc08840440d5121035244d8fd45a857becf3b7bbRobert Berry    private static final String SQL_DELETE_USER_METADATA_ENTRY =
93bc08840440d5121035244d8fd45a857becf3b7bbRobert Berry            "DROP TABLE IF EXISTS " + UserMetadataEntry.TABLE_NAME;
94bc08840440d5121035244d8fd45a857becf3b7bbRobert Berry
9577183effbf21cbaa9dd81b31ba5c0e1a580619a3Dmitry Dementyev    private static final String SQL_DELETE_RECOVERY_SERVICE_METADATA_ENTRY =
96584b923fb7d92a735209ec30b2c5e7d4b8e673ebBo Zhu            "DROP TABLE IF EXISTS " + RecoveryServiceMetadataEntry.TABLE_NAME;
975b81fa66e8efc2b8ed54973a5f1b1bbd6d7a7b3eBo Zhu
98f34fc7e18c2a2ec5cff0bd9d96397311745fbef4Dmitry Dementyev    private static final String SQL_DELETE_ROOT_OF_TRUST_ENTRY =
99f34fc7e18c2a2ec5cff0bd9d96397311745fbef4Dmitry Dementyev            "DROP TABLE IF EXISTS " + RootOfTrustEntry.TABLE_NAME;
100f34fc7e18c2a2ec5cff0bd9d96397311745fbef4Dmitry Dementyev
10176cf0831e030e42ffc0ffa24abd58350eea046e9Robert Berry    RecoverableKeyStoreDbHelper(Context context) {
10276cf0831e030e42ffc0ffa24abd58350eea046e9Robert Berry        super(context, DATABASE_NAME, null, DATABASE_VERSION);
10376cf0831e030e42ffc0ffa24abd58350eea046e9Robert Berry    }
10476cf0831e030e42ffc0ffa24abd58350eea046e9Robert Berry
10576cf0831e030e42ffc0ffa24abd58350eea046e9Robert Berry    @Override
10676cf0831e030e42ffc0ffa24abd58350eea046e9Robert Berry    public void onCreate(SQLiteDatabase db) {
107bc08840440d5121035244d8fd45a857becf3b7bbRobert Berry        db.execSQL(SQL_CREATE_KEYS_ENTRY);
108bc08840440d5121035244d8fd45a857becf3b7bbRobert Berry        db.execSQL(SQL_CREATE_USER_METADATA_ENTRY);
10977183effbf21cbaa9dd81b31ba5c0e1a580619a3Dmitry Dementyev        db.execSQL(SQL_CREATE_RECOVERY_SERVICE_METADATA_ENTRY);
110f34fc7e18c2a2ec5cff0bd9d96397311745fbef4Dmitry Dementyev        db.execSQL(SQL_CREATE_ROOT_OF_TRUST_ENTRY);
111f34fc7e18c2a2ec5cff0bd9d96397311745fbef4Dmitry Dementyev    }
112f34fc7e18c2a2ec5cff0bd9d96397311745fbef4Dmitry Dementyev
113f34fc7e18c2a2ec5cff0bd9d96397311745fbef4Dmitry Dementyev    @Override
114f34fc7e18c2a2ec5cff0bd9d96397311745fbef4Dmitry Dementyev    public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {
115f34fc7e18c2a2ec5cff0bd9d96397311745fbef4Dmitry Dementyev        Log.e(TAG, "Recreating recoverablekeystore after unexpected version downgrade.");
116f34fc7e18c2a2ec5cff0bd9d96397311745fbef4Dmitry Dementyev        dropAllKnownTables(db); // Wipe database.
117f34fc7e18c2a2ec5cff0bd9d96397311745fbef4Dmitry Dementyev        onCreate(db);
11876cf0831e030e42ffc0ffa24abd58350eea046e9Robert Berry    }
11976cf0831e030e42ffc0ffa24abd58350eea046e9Robert Berry
12076cf0831e030e42ffc0ffa24abd58350eea046e9Robert Berry    @Override
12176cf0831e030e42ffc0ffa24abd58350eea046e9Robert Berry    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
12214d993dc2c0bbdee6a6ae0c270a92107c9f57a84Bo Zhu        if (oldVersion < 2) {
123f34fc7e18c2a2ec5cff0bd9d96397311745fbef4Dmitry Dementyev            dropAllKnownTables(db); // Wipe database.
12414d993dc2c0bbdee6a6ae0c270a92107c9f57a84Bo Zhu            onCreate(db);
12514d993dc2c0bbdee6a6ae0c270a92107c9f57a84Bo Zhu            return;
12614d993dc2c0bbdee6a6ae0c270a92107c9f57a84Bo Zhu        }
12714d993dc2c0bbdee6a6ae0c270a92107c9f57a84Bo Zhu
128f34fc7e18c2a2ec5cff0bd9d96397311745fbef4Dmitry Dementyev        if (oldVersion < 3 && newVersion >= 3) {
12914d993dc2c0bbdee6a6ae0c270a92107c9f57a84Bo Zhu            upgradeDbForVersion3(db);
130f34fc7e18c2a2ec5cff0bd9d96397311745fbef4Dmitry Dementyev            oldVersion = 3;
131f34fc7e18c2a2ec5cff0bd9d96397311745fbef4Dmitry Dementyev        }
132f34fc7e18c2a2ec5cff0bd9d96397311745fbef4Dmitry Dementyev
133f34fc7e18c2a2ec5cff0bd9d96397311745fbef4Dmitry Dementyev        if (oldVersion < 4 && newVersion >= 4) {
134f34fc7e18c2a2ec5cff0bd9d96397311745fbef4Dmitry Dementyev            upgradeDbForVersion4(db);
135f34fc7e18c2a2ec5cff0bd9d96397311745fbef4Dmitry Dementyev            oldVersion = 4;
13614d993dc2c0bbdee6a6ae0c270a92107c9f57a84Bo Zhu        }
137f34fc7e18c2a2ec5cff0bd9d96397311745fbef4Dmitry Dementyev
138f34fc7e18c2a2ec5cff0bd9d96397311745fbef4Dmitry Dementyev        if (oldVersion != newVersion) {
139f34fc7e18c2a2ec5cff0bd9d96397311745fbef4Dmitry Dementyev            Log.e(TAG, "Failed to update recoverablekeystore database to the most recent version");
140f34fc7e18c2a2ec5cff0bd9d96397311745fbef4Dmitry Dementyev        }
141f34fc7e18c2a2ec5cff0bd9d96397311745fbef4Dmitry Dementyev    }
142f34fc7e18c2a2ec5cff0bd9d96397311745fbef4Dmitry Dementyev
143f34fc7e18c2a2ec5cff0bd9d96397311745fbef4Dmitry Dementyev    private void dropAllKnownTables(SQLiteDatabase db) {
144f34fc7e18c2a2ec5cff0bd9d96397311745fbef4Dmitry Dementyev            db.execSQL(SQL_DELETE_KEYS_ENTRY);
145f34fc7e18c2a2ec5cff0bd9d96397311745fbef4Dmitry Dementyev            db.execSQL(SQL_DELETE_USER_METADATA_ENTRY);
146f34fc7e18c2a2ec5cff0bd9d96397311745fbef4Dmitry Dementyev            db.execSQL(SQL_DELETE_RECOVERY_SERVICE_METADATA_ENTRY);
147f34fc7e18c2a2ec5cff0bd9d96397311745fbef4Dmitry Dementyev            db.execSQL(SQL_DELETE_ROOT_OF_TRUST_ENTRY);
14814d993dc2c0bbdee6a6ae0c270a92107c9f57a84Bo Zhu    }
14914d993dc2c0bbdee6a6ae0c270a92107c9f57a84Bo Zhu
15014d993dc2c0bbdee6a6ae0c270a92107c9f57a84Bo Zhu    private void upgradeDbForVersion3(SQLiteDatabase db) {
15114d993dc2c0bbdee6a6ae0c270a92107c9f57a84Bo Zhu        // Add the two columns for cert path and cert serial number
15214d993dc2c0bbdee6a6ae0c270a92107c9f57a84Bo Zhu        addColumnToTable(db, RecoveryServiceMetadataEntry.TABLE_NAME,
15314d993dc2c0bbdee6a6ae0c270a92107c9f57a84Bo Zhu                RecoveryServiceMetadataEntry.COLUMN_NAME_CERT_PATH, "BLOB", /*defaultStr=*/ null);
15414d993dc2c0bbdee6a6ae0c270a92107c9f57a84Bo Zhu        addColumnToTable(db, RecoveryServiceMetadataEntry.TABLE_NAME,
15514d993dc2c0bbdee6a6ae0c270a92107c9f57a84Bo Zhu                RecoveryServiceMetadataEntry.COLUMN_NAME_CERT_SERIAL, "INTEGER", /*defaultStr=*/
15614d993dc2c0bbdee6a6ae0c270a92107c9f57a84Bo Zhu                null);
15714d993dc2c0bbdee6a6ae0c270a92107c9f57a84Bo Zhu    }
15814d993dc2c0bbdee6a6ae0c270a92107c9f57a84Bo Zhu
159f34fc7e18c2a2ec5cff0bd9d96397311745fbef4Dmitry Dementyev    private void upgradeDbForVersion4(SQLiteDatabase db) {
160f34fc7e18c2a2ec5cff0bd9d96397311745fbef4Dmitry Dementyev        Log.d(TAG, "Updating recoverable keystore database to version 4");
161f34fc7e18c2a2ec5cff0bd9d96397311745fbef4Dmitry Dementyev        // Add new table with two columns for cert path and cert serial number.
162f34fc7e18c2a2ec5cff0bd9d96397311745fbef4Dmitry Dementyev        db.execSQL(SQL_CREATE_ROOT_OF_TRUST_ENTRY);
163f34fc7e18c2a2ec5cff0bd9d96397311745fbef4Dmitry Dementyev        // adds column to store root of trust currently used by the recovery agent
164f34fc7e18c2a2ec5cff0bd9d96397311745fbef4Dmitry Dementyev        addColumnToTable(db, RecoveryServiceMetadataEntry.TABLE_NAME,
165f34fc7e18c2a2ec5cff0bd9d96397311745fbef4Dmitry Dementyev                RecoveryServiceMetadataEntry.COLUMN_NAME_ACTIVE_ROOT_OF_TRUST, "TEXT",
166f34fc7e18c2a2ec5cff0bd9d96397311745fbef4Dmitry Dementyev                /*defaultStr=*/ null);
167f34fc7e18c2a2ec5cff0bd9d96397311745fbef4Dmitry Dementyev    }
168f34fc7e18c2a2ec5cff0bd9d96397311745fbef4Dmitry Dementyev
16914d993dc2c0bbdee6a6ae0c270a92107c9f57a84Bo Zhu    private static void addColumnToTable(
17014d993dc2c0bbdee6a6ae0c270a92107c9f57a84Bo Zhu            SQLiteDatabase db, String tableName, String column, String columnType,
17114d993dc2c0bbdee6a6ae0c270a92107c9f57a84Bo Zhu            String defaultStr) {
17214d993dc2c0bbdee6a6ae0c270a92107c9f57a84Bo Zhu        Log.d(TAG, "Adding column " + column + " to " + tableName + ".");
17314d993dc2c0bbdee6a6ae0c270a92107c9f57a84Bo Zhu
17414d993dc2c0bbdee6a6ae0c270a92107c9f57a84Bo Zhu        String alterStr = "ALTER TABLE " + tableName + " ADD COLUMN " + column + " " + columnType;
17514d993dc2c0bbdee6a6ae0c270a92107c9f57a84Bo Zhu        if (defaultStr != null && !defaultStr.isEmpty()) {
17614d993dc2c0bbdee6a6ae0c270a92107c9f57a84Bo Zhu            alterStr += " DEFAULT " + defaultStr;
17714d993dc2c0bbdee6a6ae0c270a92107c9f57a84Bo Zhu        }
17814d993dc2c0bbdee6a6ae0c270a92107c9f57a84Bo Zhu
17914d993dc2c0bbdee6a6ae0c270a92107c9f57a84Bo Zhu        db.execSQL(alterStr + ";");
18076cf0831e030e42ffc0ffa24abd58350eea046e9Robert Berry    }
18176cf0831e030e42ffc0ffa24abd58350eea046e9Robert Berry}
18214d993dc2c0bbdee6a6ae0c270a92107c9f57a84Bo Zhu
183