Loading services/core/java/com/android/server/appop/DiscreteOpsMigrationHelper.java +29 −0 Original line number Diff line number Diff line Loading @@ -117,6 +117,35 @@ public class DiscreteOpsMigrationHelper { } } /** * rollback discrete ops from unified schema sqlite to xml schema. */ static void rollbackFromUnifiedSchemaSqliteToXml(AppOpHistoryHelper sourceRegistry, DiscreteOpsXmlRegistry targetRegistry) { try { List<AggregatedAppOpAccessEvent> unifiedSchemaSqliteOps = sourceRegistry.getAppOpHistory(); List<DiscreteOpsSqlRegistry.DiscreteOp> discreteOps = new ArrayList<>(); for (AggregatedAppOpAccessEvent event : unifiedSchemaSqliteOps) { discreteOps.add(new DiscreteOpsSqlRegistry.DiscreteOp(event.uid(), event.packageName(), event.attributionTag(), event.deviceId(), event.opCode(), event.opFlags(), event.attributionFlags(), event.uidState(), event.attributionChainId(), event.accessTimeMillis(), event.durationMillis())); } DiscreteOpsXmlRegistry.DiscreteOps xmlOps = getXmlDiscreteOps(discreteOps); targetRegistry.migrateDiscreteAppOpHistory(xmlOps); if (!sourceRegistry.deleteDatabase()) { Slog.w(LOG_TAG, "Couldn't delete appops unified sql database."); } } catch (Exception ex) { Slog.e(LOG_TAG, "rollbackFromUnifiedSchemaSqliteToXml failed.", ex); sourceRegistry.deleteDatabase(); } } /** * rollback discrete ops from sqlite to xml. */ Loading services/core/java/com/android/server/appop/HistoricalRegistry.java +15 −0 Original line number Diff line number Diff line Loading @@ -237,15 +237,21 @@ public class HistoricalRegistry implements HistoricalRegistryInterface { mHistoryRetentionMillis); // migrate discrete ops from xml or sqlite to unified-schema sqlite database. if (DiscreteOpsXmlRegistry.getDiscreteOpsDir().exists()) { Slog.i(TAG, "migrate discrete ops from xml to unified sqlite."); DiscreteOpsXmlRegistry xmlRegistry = new DiscreteOpsXmlRegistry(mContext); DiscreteOpsMigrationHelper.migrateFromXmlToUnifiedSchemaSqlite( xmlRegistry, mShortIntervalHistoryHelper); } else if (DiscreteOpsDbHelper.getDatabaseFile().exists()) { Slog.i(TAG, "migrate discrete ops from sqlite to unified sqlite."); DiscreteOpsSqlRegistry sqlRegistry = new DiscreteOpsSqlRegistry(mContext); DiscreteOpsMigrationHelper.migrateFromSqliteToUnifiedSchemaSqlite( sqlRegistry, mShortIntervalHistoryHelper); } if (LegacyHistoricalRegistry.historicalOpsDirExist()) { LegacyHistoricalRegistry.deleteHistoricalOpsDir(); } mChainIdOffset = mShortIntervalHistoryHelper.getLargestAttributionChainId(); // Set up listener for quantization, op flags or app ops list config for testing Loading Loading @@ -686,6 +692,15 @@ public class HistoricalRegistry implements HistoricalRegistryInterface { mIsReady = true; } static boolean historicalOpsDbExist() { return getDatabaseFile(LONG_INTERVAL_DATABASE_FILE).exists(); } static void deleteHistoricalOpsDb(Context context) { context.deleteDatabase(getDatabaseFile(LONG_INTERVAL_DATABASE_FILE).getAbsolutePath()); } @NonNull // This is used during rollback in LegacyHistoricalRegistry, will be removed during flag // cleanup Loading services/core/java/com/android/server/appop/LegacyHistoricalRegistry.java +35 −8 Original line number Diff line number Diff line Loading @@ -262,32 +262,51 @@ final class LegacyHistoricalRegistry implements HistoricalRegistryInterface { if (Flags.enableSqliteAppopsAccesses()) { DiscreteOpsSqlRegistry sqlRegistry = (DiscreteOpsSqlRegistry) mDiscreteRegistry; if (DiscreteOpsXmlRegistry.getDiscreteOpsDir().exists()) { Slog.i(LOG_TAG, "migrate discrete ops from xml to sqlite."); DiscreteOpsXmlRegistry xmlRegistry = new DiscreteOpsXmlRegistry(mContext); xmlRegistry.systemReady(); DiscreteOpsMigrationHelper.migrateFromXmlToSqlite( xmlRegistry, sqlRegistry); } else if (HistoricalRegistry.getDiscreteOpsDatabaseFile().exists()) { // roll back from unified schema sqlite to discrete ops sqlite. AppOpHistoryHelper appOpHistoryHelper = new AppOpHistoryHelper(mContext, HistoricalRegistry.getDiscreteOpsDatabaseFile(), HistoricalRegistry.AggregationTimeWindow.SHORT, HistoricalRegistry.getDiscreteOpsDatabaseVersion()); appOpHistoryHelper.systemReady( HistoricalRegistry.getDiscreteOpsQuantizationMillis(), HistoricalRegistry.getAppOpsHistoryRetentionMillis()); Slog.i(LOG_TAG, "rollback discrete ops from unified sqlite to sqlite."); AppOpHistoryHelper appOpHistoryHelper = getAppOpHistoryHelper(); DiscreteOpsMigrationHelper.rollbackFromUnifiedSchemaSqliteToSqlite( appOpHistoryHelper, sqlRegistry); } } else { if (DiscreteOpsDbHelper.getDatabaseFile().exists()) { // roll-back sqlite to xml if (HistoricalRegistry.getDiscreteOpsDatabaseFile().exists()) { Slog.i(LOG_TAG, "rollback discrete ops from unified sqlite to xml."); DiscreteOpsXmlRegistry xmlRegistry = new DiscreteOpsXmlRegistry(mContext); AppOpHistoryHelper appOpHistoryHelper = getAppOpHistoryHelper(); DiscreteOpsMigrationHelper.rollbackFromUnifiedSchemaSqliteToXml( appOpHistoryHelper, xmlRegistry); if (HistoricalRegistry.historicalOpsDbExist()) { HistoricalRegistry.deleteHistoricalOpsDb(mContext); } } else if (DiscreteOpsDbHelper.getDatabaseFile().exists()) { Slog.i(LOG_TAG, "rollback discrete ops from sqlite to xml."); DiscreteOpsSqlRegistry sqlRegistry = new DiscreteOpsSqlRegistry(mContext); sqlRegistry.systemReady(); DiscreteOpsXmlRegistry xmlRegistry = (DiscreteOpsXmlRegistry) mDiscreteRegistry; DiscreteOpsMigrationHelper.rollbackFromSqliteToXml(sqlRegistry, xmlRegistry); } } } private @NonNull AppOpHistoryHelper getAppOpHistoryHelper() { AppOpHistoryHelper appOpHistoryHelper = new AppOpHistoryHelper(mContext, HistoricalRegistry.getDiscreteOpsDatabaseFile(), HistoricalRegistry.AggregationTimeWindow.SHORT, HistoricalRegistry.getDiscreteOpsDatabaseVersion()); appOpHistoryHelper.systemReady( HistoricalRegistry.getDiscreteOpsQuantizationMillis(), HistoricalRegistry.getAppOpsHistoryRetentionMillis()); return appOpHistoryHelper; } private boolean isPersistenceInitializedMLocked() { return mPersistence != null; } Loading Loading @@ -864,6 +883,14 @@ final class LegacyHistoricalRegistry implements HistoricalRegistryInterface { } } static boolean historicalOpsDirExist() { return Persistence.sHistoricalAppOpsDir.exists(); } static void deleteHistoricalOpsDir() { Persistence.sHistoricalAppOpsDir.delete(); } private static final class Persistence { private static final boolean DEBUG = false; Loading services/tests/servicestests/src/com/android/server/appop/DiscreteOpsMigrationAndRollbackTest.java +32 −0 Original line number Diff line number Diff line Loading @@ -232,6 +232,38 @@ public class DiscreteOpsMigrationAndRollbackTest { assertThat(appOpHistoryHelper.getLargestAttributionChainId()).isEqualTo(RECORD_COUNT); } @Test public void rollbackFromUnifiedSchemaSqliteToXml() { // write to unified schema sqlite registry AppOpHistoryHelper appOpHistoryHelper = new AppOpHistoryHelper(mContext, mContext.getDatabasePath(DISCRETE_OPS_UNIFIED_SCHEMA_DB_NAME), HistoricalRegistry.AggregationTimeWindow.SHORT, 1); appOpHistoryHelper.systemReady(Duration.ofMinutes(1).toMillis(), Duration.ofDays(7).toMillis()); for (int i = 1; i <= RECORD_COUNT; i++) { appOpHistoryHelper.incrementOpAccessedCount(AppOpsManager.OP_COARSE_LOCATION, RECORD_COUNT + i, mContext.getPackageName(), VirtualDeviceManager.PERSISTENT_DEVICE_ID_DEFAULT, null, UID_STATE_FOREGROUND, AppOpsManager.OP_FLAG_SELF, System.currentTimeMillis(), ATTRIBUTION_FLAG_ACCESSOR, i, 1, false); } // flush records from cache to the database. appOpHistoryHelper.shutdown(); assertThat(appOpHistoryHelper.getAppOpHistory().size()).isEqualTo(RECORD_COUNT); assertThat(appOpHistoryHelper.getLargestAttributionChainId()).isEqualTo(RECORD_COUNT); // now rollback to xml registry DiscreteOpsXmlRegistry xmlRegistry = new DiscreteOpsXmlRegistry(mLock, mMockDataDirectory); xmlRegistry.systemReady(); DiscreteOpsMigrationHelper.rollbackFromUnifiedSchemaSqliteToXml( appOpHistoryHelper, xmlRegistry); DiscreteOpsXmlRegistry.DiscreteOps xmlOps = xmlRegistry.getAllDiscreteOps(); assertThat(appOpHistoryHelper.getAppOpHistory()).isEmpty(); assertThat(xmlOps.mLargestChainId).isEqualTo(RECORD_COUNT); assertThat(xmlOps.mUids.size()).isEqualTo(RECORD_COUNT); } private static class DiscreteOpBuilder { private int mUid; private String mPackageName; Loading Loading
services/core/java/com/android/server/appop/DiscreteOpsMigrationHelper.java +29 −0 Original line number Diff line number Diff line Loading @@ -117,6 +117,35 @@ public class DiscreteOpsMigrationHelper { } } /** * rollback discrete ops from unified schema sqlite to xml schema. */ static void rollbackFromUnifiedSchemaSqliteToXml(AppOpHistoryHelper sourceRegistry, DiscreteOpsXmlRegistry targetRegistry) { try { List<AggregatedAppOpAccessEvent> unifiedSchemaSqliteOps = sourceRegistry.getAppOpHistory(); List<DiscreteOpsSqlRegistry.DiscreteOp> discreteOps = new ArrayList<>(); for (AggregatedAppOpAccessEvent event : unifiedSchemaSqliteOps) { discreteOps.add(new DiscreteOpsSqlRegistry.DiscreteOp(event.uid(), event.packageName(), event.attributionTag(), event.deviceId(), event.opCode(), event.opFlags(), event.attributionFlags(), event.uidState(), event.attributionChainId(), event.accessTimeMillis(), event.durationMillis())); } DiscreteOpsXmlRegistry.DiscreteOps xmlOps = getXmlDiscreteOps(discreteOps); targetRegistry.migrateDiscreteAppOpHistory(xmlOps); if (!sourceRegistry.deleteDatabase()) { Slog.w(LOG_TAG, "Couldn't delete appops unified sql database."); } } catch (Exception ex) { Slog.e(LOG_TAG, "rollbackFromUnifiedSchemaSqliteToXml failed.", ex); sourceRegistry.deleteDatabase(); } } /** * rollback discrete ops from sqlite to xml. */ Loading
services/core/java/com/android/server/appop/HistoricalRegistry.java +15 −0 Original line number Diff line number Diff line Loading @@ -237,15 +237,21 @@ public class HistoricalRegistry implements HistoricalRegistryInterface { mHistoryRetentionMillis); // migrate discrete ops from xml or sqlite to unified-schema sqlite database. if (DiscreteOpsXmlRegistry.getDiscreteOpsDir().exists()) { Slog.i(TAG, "migrate discrete ops from xml to unified sqlite."); DiscreteOpsXmlRegistry xmlRegistry = new DiscreteOpsXmlRegistry(mContext); DiscreteOpsMigrationHelper.migrateFromXmlToUnifiedSchemaSqlite( xmlRegistry, mShortIntervalHistoryHelper); } else if (DiscreteOpsDbHelper.getDatabaseFile().exists()) { Slog.i(TAG, "migrate discrete ops from sqlite to unified sqlite."); DiscreteOpsSqlRegistry sqlRegistry = new DiscreteOpsSqlRegistry(mContext); DiscreteOpsMigrationHelper.migrateFromSqliteToUnifiedSchemaSqlite( sqlRegistry, mShortIntervalHistoryHelper); } if (LegacyHistoricalRegistry.historicalOpsDirExist()) { LegacyHistoricalRegistry.deleteHistoricalOpsDir(); } mChainIdOffset = mShortIntervalHistoryHelper.getLargestAttributionChainId(); // Set up listener for quantization, op flags or app ops list config for testing Loading Loading @@ -686,6 +692,15 @@ public class HistoricalRegistry implements HistoricalRegistryInterface { mIsReady = true; } static boolean historicalOpsDbExist() { return getDatabaseFile(LONG_INTERVAL_DATABASE_FILE).exists(); } static void deleteHistoricalOpsDb(Context context) { context.deleteDatabase(getDatabaseFile(LONG_INTERVAL_DATABASE_FILE).getAbsolutePath()); } @NonNull // This is used during rollback in LegacyHistoricalRegistry, will be removed during flag // cleanup Loading
services/core/java/com/android/server/appop/LegacyHistoricalRegistry.java +35 −8 Original line number Diff line number Diff line Loading @@ -262,32 +262,51 @@ final class LegacyHistoricalRegistry implements HistoricalRegistryInterface { if (Flags.enableSqliteAppopsAccesses()) { DiscreteOpsSqlRegistry sqlRegistry = (DiscreteOpsSqlRegistry) mDiscreteRegistry; if (DiscreteOpsXmlRegistry.getDiscreteOpsDir().exists()) { Slog.i(LOG_TAG, "migrate discrete ops from xml to sqlite."); DiscreteOpsXmlRegistry xmlRegistry = new DiscreteOpsXmlRegistry(mContext); xmlRegistry.systemReady(); DiscreteOpsMigrationHelper.migrateFromXmlToSqlite( xmlRegistry, sqlRegistry); } else if (HistoricalRegistry.getDiscreteOpsDatabaseFile().exists()) { // roll back from unified schema sqlite to discrete ops sqlite. AppOpHistoryHelper appOpHistoryHelper = new AppOpHistoryHelper(mContext, HistoricalRegistry.getDiscreteOpsDatabaseFile(), HistoricalRegistry.AggregationTimeWindow.SHORT, HistoricalRegistry.getDiscreteOpsDatabaseVersion()); appOpHistoryHelper.systemReady( HistoricalRegistry.getDiscreteOpsQuantizationMillis(), HistoricalRegistry.getAppOpsHistoryRetentionMillis()); Slog.i(LOG_TAG, "rollback discrete ops from unified sqlite to sqlite."); AppOpHistoryHelper appOpHistoryHelper = getAppOpHistoryHelper(); DiscreteOpsMigrationHelper.rollbackFromUnifiedSchemaSqliteToSqlite( appOpHistoryHelper, sqlRegistry); } } else { if (DiscreteOpsDbHelper.getDatabaseFile().exists()) { // roll-back sqlite to xml if (HistoricalRegistry.getDiscreteOpsDatabaseFile().exists()) { Slog.i(LOG_TAG, "rollback discrete ops from unified sqlite to xml."); DiscreteOpsXmlRegistry xmlRegistry = new DiscreteOpsXmlRegistry(mContext); AppOpHistoryHelper appOpHistoryHelper = getAppOpHistoryHelper(); DiscreteOpsMigrationHelper.rollbackFromUnifiedSchemaSqliteToXml( appOpHistoryHelper, xmlRegistry); if (HistoricalRegistry.historicalOpsDbExist()) { HistoricalRegistry.deleteHistoricalOpsDb(mContext); } } else if (DiscreteOpsDbHelper.getDatabaseFile().exists()) { Slog.i(LOG_TAG, "rollback discrete ops from sqlite to xml."); DiscreteOpsSqlRegistry sqlRegistry = new DiscreteOpsSqlRegistry(mContext); sqlRegistry.systemReady(); DiscreteOpsXmlRegistry xmlRegistry = (DiscreteOpsXmlRegistry) mDiscreteRegistry; DiscreteOpsMigrationHelper.rollbackFromSqliteToXml(sqlRegistry, xmlRegistry); } } } private @NonNull AppOpHistoryHelper getAppOpHistoryHelper() { AppOpHistoryHelper appOpHistoryHelper = new AppOpHistoryHelper(mContext, HistoricalRegistry.getDiscreteOpsDatabaseFile(), HistoricalRegistry.AggregationTimeWindow.SHORT, HistoricalRegistry.getDiscreteOpsDatabaseVersion()); appOpHistoryHelper.systemReady( HistoricalRegistry.getDiscreteOpsQuantizationMillis(), HistoricalRegistry.getAppOpsHistoryRetentionMillis()); return appOpHistoryHelper; } private boolean isPersistenceInitializedMLocked() { return mPersistence != null; } Loading Loading @@ -864,6 +883,14 @@ final class LegacyHistoricalRegistry implements HistoricalRegistryInterface { } } static boolean historicalOpsDirExist() { return Persistence.sHistoricalAppOpsDir.exists(); } static void deleteHistoricalOpsDir() { Persistence.sHistoricalAppOpsDir.delete(); } private static final class Persistence { private static final boolean DEBUG = false; Loading
services/tests/servicestests/src/com/android/server/appop/DiscreteOpsMigrationAndRollbackTest.java +32 −0 Original line number Diff line number Diff line Loading @@ -232,6 +232,38 @@ public class DiscreteOpsMigrationAndRollbackTest { assertThat(appOpHistoryHelper.getLargestAttributionChainId()).isEqualTo(RECORD_COUNT); } @Test public void rollbackFromUnifiedSchemaSqliteToXml() { // write to unified schema sqlite registry AppOpHistoryHelper appOpHistoryHelper = new AppOpHistoryHelper(mContext, mContext.getDatabasePath(DISCRETE_OPS_UNIFIED_SCHEMA_DB_NAME), HistoricalRegistry.AggregationTimeWindow.SHORT, 1); appOpHistoryHelper.systemReady(Duration.ofMinutes(1).toMillis(), Duration.ofDays(7).toMillis()); for (int i = 1; i <= RECORD_COUNT; i++) { appOpHistoryHelper.incrementOpAccessedCount(AppOpsManager.OP_COARSE_LOCATION, RECORD_COUNT + i, mContext.getPackageName(), VirtualDeviceManager.PERSISTENT_DEVICE_ID_DEFAULT, null, UID_STATE_FOREGROUND, AppOpsManager.OP_FLAG_SELF, System.currentTimeMillis(), ATTRIBUTION_FLAG_ACCESSOR, i, 1, false); } // flush records from cache to the database. appOpHistoryHelper.shutdown(); assertThat(appOpHistoryHelper.getAppOpHistory().size()).isEqualTo(RECORD_COUNT); assertThat(appOpHistoryHelper.getLargestAttributionChainId()).isEqualTo(RECORD_COUNT); // now rollback to xml registry DiscreteOpsXmlRegistry xmlRegistry = new DiscreteOpsXmlRegistry(mLock, mMockDataDirectory); xmlRegistry.systemReady(); DiscreteOpsMigrationHelper.rollbackFromUnifiedSchemaSqliteToXml( appOpHistoryHelper, xmlRegistry); DiscreteOpsXmlRegistry.DiscreteOps xmlOps = xmlRegistry.getAllDiscreteOps(); assertThat(appOpHistoryHelper.getAppOpHistory()).isEmpty(); assertThat(xmlOps.mLargestChainId).isEqualTo(RECORD_COUNT); assertThat(xmlOps.mUids.size()).isEqualTo(RECORD_COUNT); } private static class DiscreteOpBuilder { private int mUid; private String mPackageName; Loading