Make BatteryDatabaseManager singleton

In BatteryTipLoader, two threads may access BatteryDatabaseManager
simultaneously. In this case thread A may close the database thread B
holds, then settings will crash.

In this cl, we make the BatteryDatabaseManager as singleton and
synchronize all the database related method. Then it shouldn't have
the crash anymore.

Bug: 73346734
Test: RunSettingsRoboTests
Change-Id: Ib53b2894b25155cca0c6ec60d1a816663d27a578
This commit is contained in:
jackqdyulei
2018-02-14 12:43:09 -08:00
parent 1bbe424e6e
commit c76bb78758
5 changed files with 35 additions and 9 deletions

View File

@@ -38,14 +38,26 @@ import java.util.List;
/**
* Database manager for battery data. Now it only contains anomaly data stored in {@link AppInfo}.
*
* This manager may be accessed by multi-threads. All the database related methods are synchronized
* so each operation won't be interfered by other threads.
*/
public class BatteryDatabaseManager {
private final AnomalyDatabaseHelper mDatabaseHelper;
private static BatteryDatabaseManager sSingleton;
public BatteryDatabaseManager(Context context) {
private AnomalyDatabaseHelper mDatabaseHelper;
private BatteryDatabaseManager(Context context) {
mDatabaseHelper = AnomalyDatabaseHelper.getInstance(context);
}
public static BatteryDatabaseManager getInstance(Context context) {
if (sSingleton == null) {
sSingleton = new BatteryDatabaseManager(context);
}
return sSingleton;
}
/**
* Insert an anomaly log to database.
*
@@ -53,7 +65,7 @@ public class BatteryDatabaseManager {
* @param type the type of the anomaly
* @param timestampMs the time when it is happened
*/
public void insertAnomaly(String packageName, int type, long timestampMs) {
public synchronized void insertAnomaly(String packageName, int type, long timestampMs) {
try (SQLiteDatabase db = mDatabaseHelper.getWritableDatabase()) {
ContentValues values = new ContentValues();
values.put(PACKAGE_NAME, packageName);
@@ -67,7 +79,7 @@ public class BatteryDatabaseManager {
/**
* Query all the anomalies that happened after {@code timestampMsAfter} and with {@code state}.
*/
public List<AppInfo> queryAllAnomalies(long timestampMsAfter, int state) {
public synchronized List<AppInfo> queryAllAnomalies(long timestampMsAfter, int state) {
final List<AppInfo> appInfos = new ArrayList<>();
try (SQLiteDatabase db = mDatabaseHelper.getReadableDatabase()) {
final String[] projection = {PACKAGE_NAME, ANOMALY_TYPE};
@@ -90,7 +102,7 @@ public class BatteryDatabaseManager {
return appInfos;
}
public void deleteAllAnomaliesBeforeTimeStamp(long timestampMs) {
public synchronized void deleteAllAnomaliesBeforeTimeStamp(long timestampMs) {
try (SQLiteDatabase db = mDatabaseHelper.getWritableDatabase()) {
db.delete(TABLE_ANOMALY, TIME_STAMP_MS + " < ?",
new String[]{String.valueOf(timestampMs)});
@@ -103,7 +115,7 @@ public class BatteryDatabaseManager {
* @param appInfos represents the anomalies
* @param state which state to update to
*/
public void updateAnomalies(List<AppInfo> appInfos, int state) {
public synchronized void updateAnomalies(List<AppInfo> appInfos, int state) {
if (!appInfos.isEmpty()) {
final int size = appInfos.size();
final String[] whereArgs = new String[size];

View File

@@ -42,7 +42,7 @@ public class RestrictAppAction extends BatteryTipAction {
super(context);
mRestrictAppTip = tip;
mBatteryUtils = BatteryUtils.getInstance(context);
mBatteryDatabaseManager = new BatteryDatabaseManager(context);
mBatteryDatabaseManager = BatteryDatabaseManager.getInstance(context);
}
/**

View File

@@ -43,7 +43,7 @@ public class RestrictAppDetector implements BatteryTipDetector {
public RestrictAppDetector(Context context, BatteryTipPolicy policy) {
mPolicy = policy;
mBatteryDatabaseManager = new BatteryDatabaseManager(context);
mBatteryDatabaseManager = BatteryDatabaseManager.getInstance(context);
}
@Override

View File

@@ -59,7 +59,7 @@ public class BatteryDatabaseManagerTest {
MockitoAnnotations.initMocks(this);
mContext = RuntimeEnvironment.application;
mBatteryDatabaseManager = spy(new BatteryDatabaseManager(mContext));
mBatteryDatabaseManager = spy(BatteryDatabaseManager.getInstance(mContext));
}
@After

View File

@@ -19,6 +19,7 @@ package com.android.settings.testutils;
import android.content.Context;
import com.android.settings.fuelgauge.batterytip.AnomalyDatabaseHelper;
import com.android.settings.fuelgauge.batterytip.BatteryDatabaseManager;
import com.android.settings.search.IndexDatabaseHelper;
import com.android.settings.slices.SlicesDatabaseHelper;
@@ -30,6 +31,7 @@ public class DatabaseTestUtils {
clearSearchDb(context);
clearSlicesDb(context);
clearAnomalyDb(context);
clearAnomalyDbManager();
}
private static void clearSlicesDb(Context context) {
@@ -76,4 +78,16 @@ public class DatabaseTestUtils {
throw new RuntimeException();
}
}
private static void clearAnomalyDbManager() {
Field instance;
Class clazz = BatteryDatabaseManager.class;
try {
instance = clazz.getDeclaredField("sSingleton");
instance.setAccessible(true);
instance.set(null, null);
} catch (Exception e) {
throw new RuntimeException();
}
}
}