1 /* 2 * Copyright (C) 2018 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 com.android.settings.fuelgauge.batterytip; 18 19 import android.content.Context; 20 import android.database.sqlite.SQLiteDatabase; 21 import android.database.sqlite.SQLiteOpenHelper; 22 import android.util.Log; 23 24 import androidx.annotation.IntDef; 25 26 import java.lang.annotation.Retention; 27 import java.lang.annotation.RetentionPolicy; 28 29 /** Database controls the anomaly logging(e.g. packageName, anomalyType and time) */ 30 public class AnomalyDatabaseHelper extends SQLiteOpenHelper { 31 private static final String TAG = "BatteryDatabaseHelper"; 32 33 private static final String DATABASE_NAME = "battery_settings.db"; 34 private static final int DATABASE_VERSION = 5; 35 36 @Retention(RetentionPolicy.SOURCE) 37 @IntDef({State.NEW, State.HANDLED, State.AUTO_HANDLED}) 38 public @interface State { 39 int NEW = 0; 40 int HANDLED = 1; 41 int AUTO_HANDLED = 2; 42 } 43 44 @Retention(RetentionPolicy.SOURCE) 45 @IntDef({ActionType.RESTRICTION}) 46 public @interface ActionType { 47 int RESTRICTION = 0; 48 } 49 50 public interface Tables { 51 String TABLE_ANOMALY = "anomaly"; 52 String TABLE_ACTION = "action"; 53 } 54 55 public interface AnomalyColumns { 56 /** The package name of the anomaly app */ 57 String PACKAGE_NAME = "package_name"; 58 59 /** The uid of the anomaly app */ 60 String UID = "uid"; 61 62 /** 63 * The type of the anomaly app 64 * 65 * @see StatsManagerConfig.AnomalyType 66 */ 67 String ANOMALY_TYPE = "anomaly_type"; 68 69 /** 70 * The state of the anomaly app 71 * 72 * @see State 73 */ 74 String ANOMALY_STATE = "anomaly_state"; 75 76 /** The time when anomaly happens */ 77 String TIME_STAMP_MS = "time_stamp_ms"; 78 } 79 80 private static final String CREATE_ANOMALY_TABLE = 81 "CREATE TABLE " 82 + Tables.TABLE_ANOMALY 83 + "(" 84 + AnomalyColumns.UID 85 + " INTEGER NOT NULL, " 86 + AnomalyColumns.PACKAGE_NAME 87 + " TEXT, " 88 + AnomalyColumns.ANOMALY_TYPE 89 + " INTEGER NOT NULL, " 90 + AnomalyColumns.ANOMALY_STATE 91 + " INTEGER NOT NULL, " 92 + AnomalyColumns.TIME_STAMP_MS 93 + " INTEGER NOT NULL, " 94 + " PRIMARY KEY (" 95 + AnomalyColumns.UID 96 + "," 97 + AnomalyColumns.ANOMALY_TYPE 98 + "," 99 + AnomalyColumns.ANOMALY_STATE 100 + "," 101 + AnomalyColumns.TIME_STAMP_MS 102 + ")" 103 + ")"; 104 105 public interface ActionColumns { 106 /** The package name of an app been performed an action */ 107 String PACKAGE_NAME = "package_name"; 108 109 /** The uid of an app been performed an action */ 110 String UID = "uid"; 111 112 /** 113 * The type of user action 114 * 115 * @see ActionType 116 */ 117 String ACTION_TYPE = "action_type"; 118 119 /** The time when action been performed */ 120 String TIME_STAMP_MS = "time_stamp_ms"; 121 } 122 123 private static final String CREATE_ACTION_TABLE = 124 "CREATE TABLE " 125 + Tables.TABLE_ACTION 126 + "(" 127 + ActionColumns.UID 128 + " INTEGER NOT NULL, " 129 + ActionColumns.PACKAGE_NAME 130 + " TEXT, " 131 + ActionColumns.ACTION_TYPE 132 + " INTEGER NOT NULL, " 133 + ActionColumns.TIME_STAMP_MS 134 + " INTEGER NOT NULL, " 135 + " PRIMARY KEY (" 136 + ActionColumns.ACTION_TYPE 137 + "," 138 + ActionColumns.UID 139 + "," 140 + ActionColumns.PACKAGE_NAME 141 + ")" 142 + ")"; 143 144 private static AnomalyDatabaseHelper sSingleton; 145 getInstance(Context context)146 public static synchronized AnomalyDatabaseHelper getInstance(Context context) { 147 if (sSingleton == null) { 148 sSingleton = new AnomalyDatabaseHelper(context.getApplicationContext()); 149 } 150 return sSingleton; 151 } 152 AnomalyDatabaseHelper(Context context)153 private AnomalyDatabaseHelper(Context context) { 154 super(context, DATABASE_NAME, null, DATABASE_VERSION); 155 } 156 157 @Override onCreate(SQLiteDatabase db)158 public void onCreate(SQLiteDatabase db) { 159 bootstrapDB(db); 160 } 161 162 @Override onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)163 public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { 164 if (oldVersion < DATABASE_VERSION) { 165 Log.w( 166 TAG, 167 "Detected schema version '" 168 + oldVersion 169 + "'. " 170 + "Index needs to be rebuilt for schema version '" 171 + newVersion 172 + "'."); 173 // We need to drop the tables and recreate them 174 reconstruct(db); 175 } 176 } 177 178 @Override onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion)179 public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) { 180 Log.w( 181 TAG, 182 "Detected schema version '" 183 + oldVersion 184 + "'. " 185 + "Index needs to be rebuilt for schema version '" 186 + newVersion 187 + "'."); 188 // We need to drop the tables and recreate them 189 reconstruct(db); 190 } 191 reconstruct(SQLiteDatabase db)192 public void reconstruct(SQLiteDatabase db) { 193 dropTables(db); 194 bootstrapDB(db); 195 } 196 bootstrapDB(SQLiteDatabase db)197 private void bootstrapDB(SQLiteDatabase db) { 198 db.execSQL(CREATE_ANOMALY_TABLE); 199 db.execSQL(CREATE_ACTION_TABLE); 200 Log.i(TAG, "Bootstrapped database"); 201 } 202 dropTables(SQLiteDatabase db)203 private void dropTables(SQLiteDatabase db) { 204 db.execSQL("DROP TABLE IF EXISTS " + Tables.TABLE_ANOMALY); 205 db.execSQL("DROP TABLE IF EXISTS " + Tables.TABLE_ACTION); 206 } 207 } 208