Loading services/core/java/com/android/server/appop/AppOpHistoryDbHelper.java +21 −1 Original line number Diff line number Diff line Loading @@ -238,11 +238,31 @@ class AppOpHistoryDbHelper extends SQLiteOpenHelper { db.endTransaction(); } } catch (SQLiteException exception) { Slog.e(LOG_TAG, "Error reading attribution chain id", exception); Slog.e(LOG_TAG, "Error reading chain id " + mDatabaseFile.getName(), exception); } return chainId; } long getTotalRecordsCount() { long count = 0; try { SQLiteDatabase db = getReadableDatabase(); db.beginTransactionReadOnly(); try (SQLiteRawStatement statement = db.createRawStatement( AppOpHistoryTable.SELECT_RECORDS_COUNT)) { if (statement.step()) { count = statement.getColumnLong(0); } db.setTransactionSuccessful(); } finally { db.endTransaction(); } } catch (SQLiteException exception) { Slog.e(LOG_TAG, "Error reading records count " + mDatabaseFile.getName(), exception); } return count; } @VisibleForTesting List<AggregatedAppOpAccessEvent> getAppOpHistory() { List<AggregatedAppOpAccessEvent> results = new ArrayList<>(); Loading services/core/java/com/android/server/appop/AppOpHistoryHelper.java +16 −15 Original line number Diff line number Diff line Loading @@ -309,6 +309,10 @@ public class AppOpHistoryHelper { SQLITE_APP_OP_EVENT_REPORTED__WRITE_TYPE__WRITE_MIGRATION); } long getTotalRecordsCount() { return mDbHelper.getTotalRecordsCount(); } @VisibleForTesting List<AggregatedAppOpAccessEvent> getAppOpHistory() { List<AggregatedAppOpAccessEvent> ops = new ArrayList<>(); Loading Loading @@ -364,29 +368,24 @@ public class AppOpHistoryHelper { return chains; } void dump(PrintWriter pw, int filterUid, @Nullable String filterPackage, @Nullable String filterAttributionTag, int filterOp, void dump(long beginTimeMillis, long endTimeMillis, PrintWriter pw, int filterUid, @Nullable String filterPackage, @Nullable String filterAttributionTag, IntArray opCodes, @AppOpsManager.HistoricalOpsRequestFilter int filter, @NonNull SimpleDateFormat sdf, @NonNull Date date, int limit) { // flush caches to the database insertAppOpHistory(mCache.evictAll(), SQLITE_APP_OP_EVENT_REPORTED__WRITE_TYPE__WRITE_READ); long currentTime = System.currentTimeMillis(); long beginTimeMillis = discretizeTimestamp(currentTime - mHistoryRetentionMillis); IntArray opCodes = new IntArray(); if ((filter & AppOpsManager.FILTER_BY_OP_NAMES) != 0 && filterOp != AppOpsManager.OP_NONE) { opCodes.add(filterOp); } beginTimeMillis = discretizeTimestamp(beginTimeMillis); List<AggregatedAppOpAccessEvent> appOpHistoryAccesses = mDbHelper.getAppOpHistory( filter, beginTimeMillis, currentTime, filterUid, filterPackage, filter, beginTimeMillis, endTimeMillis, filterUid, filterPackage, filterAttributionTag, opCodes, AppOpsManager.OP_FLAGS_ALL, limit, AppOpHistoryTable.Columns.ACCESS_TIME, false); pw.println(); pw.println("UID|PACKAGE_NAME|DEVICE_ID|OP_NAME|ATTRIBUTION_TAG|UID_STATE|OP_FLAGS|" + "ACCESS_TIME|ACCESS_COUNTS|REJECT_COUNTS|DURATION"); pw.println("UID|PACKAGE_NAME|DEVICE_ID|OP_NAME|ATTRIBUTION_TAG|ACCESS_TIME|ACCESS_COUNTS" + "|REJECT_COUNTS|DURATION|UID_STATE|OP_FLAGS" + "|ATTRIBUTION_CHAIN_ID|ATTRIBUTION_FLAGS"); for (AggregatedAppOpAccessEvent aggAppOpAccess : appOpHistoryAccesses) { date.setTime(aggAppOpAccess.accessTimeMillis()); pw.println(aggAppOpAccess.uid() + "|" Loading @@ -394,12 +393,14 @@ public class AppOpHistoryHelper { + aggAppOpAccess.deviceId() + "|" + AppOpsManager.opToName(aggAppOpAccess.opCode()) + "|" + aggAppOpAccess.attributionTag() + "|" + getUidStateName(aggAppOpAccess.uidState()) + "|" + flagsToString(aggAppOpAccess.opFlags()) + "|" + sdf.format(date) + "|" + aggAppOpAccess.totalAccessCount() + "|" + aggAppOpAccess.totalRejectCount() + "|" + aggAppOpAccess.durationMillis()); + aggAppOpAccess.totalDurationMillis() + "|" + getUidStateName(aggAppOpAccess.uidState()) + "|" + flagsToString(aggAppOpAccess.opFlags()) + "|" + aggAppOpAccess.attributionChainId() + "|" + aggAppOpAccess.attributionFlags()); } pw.println(); } Loading services/core/java/com/android/server/appop/AppOpHistoryTable.java +2 −0 Original line number Diff line number Diff line Loading @@ -167,6 +167,8 @@ final class AppOpHistoryTable { static final String SELECT_MAX_ATTRIBUTION_CHAIN_ID = "SELECT MAX(" + Columns.CHAIN_ID + ")" + " FROM " + TABLE_NAME; static final String SELECT_RECORDS_COUNT = "SELECT COUNT(1) FROM " + TABLE_NAME; // Index on access time static final String CREATE_INDEX_SQL = "CREATE INDEX IF NOT EXISTS " + INDEX_APP_OP + " ON " + TABLE_NAME Loading services/core/java/com/android/server/appop/AppOpsService.java +4 −5 Original line number Diff line number Diff line Loading @@ -6271,7 +6271,7 @@ public class AppOpsService extends IAppOpsService.Stub { boolean dumpHistory = false; boolean includeDiscreteOps = false; boolean dumpUidStateChangeLogs = false; int historyLimit = 10; int historyLimit = 100; @HistoricalOpsRequestFilter int dumpFilter = 0; boolean dumpAll = false; Loading Loading @@ -6762,10 +6762,9 @@ public class AppOpsService extends IAppOpsService.Stub { } if (Flags.enableAllSqliteAppopsAccesses()) { if (dumpHistory && !dumpWatchers) { mHistoricalRegistry.dump("", pw, dumpUid, dumpPackage, dumpAttributionTag, dumpOp, dumpFilter, sdf, date, includeDiscreteOps, historyLimit); } dumpOp, dumpFilter, sdf, date, includeDiscreteOps, historyLimit, dumpHistory && !dumpWatchers); } else { // Must not hold the appops lock if (dumpHistory && !dumpWatchers) { Loading services/core/java/com/android/server/appop/HistoricalRegistry.java +52 −5 Original line number Diff line number Diff line Loading @@ -57,6 +57,7 @@ import android.os.AsyncTask; import android.os.Build; import android.os.Bundle; import android.os.Environment; import android.os.Process; import android.os.RemoteCallback; import android.provider.DeviceConfig; import android.provider.Settings; Loading Loading @@ -378,20 +379,66 @@ public class HistoricalRegistry implements HistoricalRegistryInterface { public void dump(String prefix, PrintWriter pw, int filterUid, @Nullable String filterPackage, @Nullable String filterAttributionTag, int filterOp, int filter, @NonNull SimpleDateFormat sdf, @NonNull Date date, boolean includeDiscreteOps, int limit) { int limit, boolean dumpHistory) { pw.println(); pw.print(prefix); pw.print("History:"); pw.print(" mode="); pw.println(AppOpsManager.historicalModeToString(mMode)); long shortIntervalMinute = Duration.ofMillis(mShortIntervalQuantizationMillis).toMinutes(); long longIntervalMinute = Duration.ofMillis(mLongIntervalQuantizationMillis).toMinutes(); pw.print("SHORT_INTERVAL(Aggregation Bucket)="); pw.print(shortIntervalMinute + " Minute"); pw.print(", LONG_INTERVAL(Aggregation Bucket)="); pw.println(longIntervalMinute + " Minutes"); pw.print("Database size(bytes): SHORT_INTERVAL="); pw.print(getDatabaseFile(SHORT_INTERVAL_DATABASE_FILE).length()); pw.print(", LONG_INTERVAL="); pw.println(getDatabaseFile(LONG_INTERVAL_DATABASE_FILE).length()); pw.print("Database Total records: SHORT_INTERVAL="); pw.print(mShortIntervalHistoryHelper.getTotalRecordsCount()); pw.print(", LONG_INTERVAL="); pw.println(mLongIntervalHistoryHelper.getTotalRecordsCount()); IntArray opCodes = new IntArray(); long endTimeMillis = System.currentTimeMillis(); if (!dumpHistory && !includeDiscreteOps) { filter = AppOpsManager.FILTER_BY_OP_NAMES; // print privacy indicator records for last 1 hour (or up to 500 records) long beginTimeMillis = endTimeMillis - Duration.ofHours(1).toMillis(); opCodes.add(OP_CAMERA); opCodes.add(OP_PHONE_CALL_CAMERA); opCodes.add(OP_RECORD_AUDIO); opCodes.add(OP_PHONE_CALL_MICROPHONE); opCodes.add(OP_RECEIVE_AMBIENT_TRIGGER_AUDIO); opCodes.add(OP_RECEIVE_SANDBOX_TRIGGER_AUDIO); opCodes.add(OP_FINE_LOCATION); opCodes.add(OP_COARSE_LOCATION); opCodes.add(OP_EMERGENCY_LOCATION); pw.println("----Location, Microphone, and Camera App Ops (Last 1 Hour)----"); mShortIntervalHistoryHelper.dump(beginTimeMillis, endTimeMillis, pw, Process.INVALID_UID, null, null, opCodes, filter, sdf, date, 500); return; } if ((filter & AppOpsManager.FILTER_BY_OP_NAMES) != 0 && filterOp != AppOpsManager.OP_NONE) { opCodes.add(filterOp); } long beginTimeMillis = endTimeMillis - mHistoryRetentionMillis; if (includeDiscreteOps) { pw.println("------------Discrete App Ops-------------"); mShortIntervalHistoryHelper.dump(pw, filterUid, filterPackage, filterAttributionTag, filterOp, filter, sdf, date, limit); mShortIntervalHistoryHelper.dump(beginTimeMillis, endTimeMillis, pw, filterUid, filterPackage, filterAttributionTag, opCodes, filter, sdf, date, limit); } else { pw.println("------------Aggregated App Ops-------------"); mLongIntervalHistoryHelper.dump(pw, filterUid, filterPackage, filterAttributionTag, filterOp, filter, sdf, date, limit); mLongIntervalHistoryHelper.dump(beginTimeMillis, endTimeMillis, pw, filterUid, filterPackage, filterAttributionTag, opCodes, filter, sdf, date, limit); } } Loading Loading
services/core/java/com/android/server/appop/AppOpHistoryDbHelper.java +21 −1 Original line number Diff line number Diff line Loading @@ -238,11 +238,31 @@ class AppOpHistoryDbHelper extends SQLiteOpenHelper { db.endTransaction(); } } catch (SQLiteException exception) { Slog.e(LOG_TAG, "Error reading attribution chain id", exception); Slog.e(LOG_TAG, "Error reading chain id " + mDatabaseFile.getName(), exception); } return chainId; } long getTotalRecordsCount() { long count = 0; try { SQLiteDatabase db = getReadableDatabase(); db.beginTransactionReadOnly(); try (SQLiteRawStatement statement = db.createRawStatement( AppOpHistoryTable.SELECT_RECORDS_COUNT)) { if (statement.step()) { count = statement.getColumnLong(0); } db.setTransactionSuccessful(); } finally { db.endTransaction(); } } catch (SQLiteException exception) { Slog.e(LOG_TAG, "Error reading records count " + mDatabaseFile.getName(), exception); } return count; } @VisibleForTesting List<AggregatedAppOpAccessEvent> getAppOpHistory() { List<AggregatedAppOpAccessEvent> results = new ArrayList<>(); Loading
services/core/java/com/android/server/appop/AppOpHistoryHelper.java +16 −15 Original line number Diff line number Diff line Loading @@ -309,6 +309,10 @@ public class AppOpHistoryHelper { SQLITE_APP_OP_EVENT_REPORTED__WRITE_TYPE__WRITE_MIGRATION); } long getTotalRecordsCount() { return mDbHelper.getTotalRecordsCount(); } @VisibleForTesting List<AggregatedAppOpAccessEvent> getAppOpHistory() { List<AggregatedAppOpAccessEvent> ops = new ArrayList<>(); Loading Loading @@ -364,29 +368,24 @@ public class AppOpHistoryHelper { return chains; } void dump(PrintWriter pw, int filterUid, @Nullable String filterPackage, @Nullable String filterAttributionTag, int filterOp, void dump(long beginTimeMillis, long endTimeMillis, PrintWriter pw, int filterUid, @Nullable String filterPackage, @Nullable String filterAttributionTag, IntArray opCodes, @AppOpsManager.HistoricalOpsRequestFilter int filter, @NonNull SimpleDateFormat sdf, @NonNull Date date, int limit) { // flush caches to the database insertAppOpHistory(mCache.evictAll(), SQLITE_APP_OP_EVENT_REPORTED__WRITE_TYPE__WRITE_READ); long currentTime = System.currentTimeMillis(); long beginTimeMillis = discretizeTimestamp(currentTime - mHistoryRetentionMillis); IntArray opCodes = new IntArray(); if ((filter & AppOpsManager.FILTER_BY_OP_NAMES) != 0 && filterOp != AppOpsManager.OP_NONE) { opCodes.add(filterOp); } beginTimeMillis = discretizeTimestamp(beginTimeMillis); List<AggregatedAppOpAccessEvent> appOpHistoryAccesses = mDbHelper.getAppOpHistory( filter, beginTimeMillis, currentTime, filterUid, filterPackage, filter, beginTimeMillis, endTimeMillis, filterUid, filterPackage, filterAttributionTag, opCodes, AppOpsManager.OP_FLAGS_ALL, limit, AppOpHistoryTable.Columns.ACCESS_TIME, false); pw.println(); pw.println("UID|PACKAGE_NAME|DEVICE_ID|OP_NAME|ATTRIBUTION_TAG|UID_STATE|OP_FLAGS|" + "ACCESS_TIME|ACCESS_COUNTS|REJECT_COUNTS|DURATION"); pw.println("UID|PACKAGE_NAME|DEVICE_ID|OP_NAME|ATTRIBUTION_TAG|ACCESS_TIME|ACCESS_COUNTS" + "|REJECT_COUNTS|DURATION|UID_STATE|OP_FLAGS" + "|ATTRIBUTION_CHAIN_ID|ATTRIBUTION_FLAGS"); for (AggregatedAppOpAccessEvent aggAppOpAccess : appOpHistoryAccesses) { date.setTime(aggAppOpAccess.accessTimeMillis()); pw.println(aggAppOpAccess.uid() + "|" Loading @@ -394,12 +393,14 @@ public class AppOpHistoryHelper { + aggAppOpAccess.deviceId() + "|" + AppOpsManager.opToName(aggAppOpAccess.opCode()) + "|" + aggAppOpAccess.attributionTag() + "|" + getUidStateName(aggAppOpAccess.uidState()) + "|" + flagsToString(aggAppOpAccess.opFlags()) + "|" + sdf.format(date) + "|" + aggAppOpAccess.totalAccessCount() + "|" + aggAppOpAccess.totalRejectCount() + "|" + aggAppOpAccess.durationMillis()); + aggAppOpAccess.totalDurationMillis() + "|" + getUidStateName(aggAppOpAccess.uidState()) + "|" + flagsToString(aggAppOpAccess.opFlags()) + "|" + aggAppOpAccess.attributionChainId() + "|" + aggAppOpAccess.attributionFlags()); } pw.println(); } Loading
services/core/java/com/android/server/appop/AppOpHistoryTable.java +2 −0 Original line number Diff line number Diff line Loading @@ -167,6 +167,8 @@ final class AppOpHistoryTable { static final String SELECT_MAX_ATTRIBUTION_CHAIN_ID = "SELECT MAX(" + Columns.CHAIN_ID + ")" + " FROM " + TABLE_NAME; static final String SELECT_RECORDS_COUNT = "SELECT COUNT(1) FROM " + TABLE_NAME; // Index on access time static final String CREATE_INDEX_SQL = "CREATE INDEX IF NOT EXISTS " + INDEX_APP_OP + " ON " + TABLE_NAME Loading
services/core/java/com/android/server/appop/AppOpsService.java +4 −5 Original line number Diff line number Diff line Loading @@ -6271,7 +6271,7 @@ public class AppOpsService extends IAppOpsService.Stub { boolean dumpHistory = false; boolean includeDiscreteOps = false; boolean dumpUidStateChangeLogs = false; int historyLimit = 10; int historyLimit = 100; @HistoricalOpsRequestFilter int dumpFilter = 0; boolean dumpAll = false; Loading Loading @@ -6762,10 +6762,9 @@ public class AppOpsService extends IAppOpsService.Stub { } if (Flags.enableAllSqliteAppopsAccesses()) { if (dumpHistory && !dumpWatchers) { mHistoricalRegistry.dump("", pw, dumpUid, dumpPackage, dumpAttributionTag, dumpOp, dumpFilter, sdf, date, includeDiscreteOps, historyLimit); } dumpOp, dumpFilter, sdf, date, includeDiscreteOps, historyLimit, dumpHistory && !dumpWatchers); } else { // Must not hold the appops lock if (dumpHistory && !dumpWatchers) { Loading
services/core/java/com/android/server/appop/HistoricalRegistry.java +52 −5 Original line number Diff line number Diff line Loading @@ -57,6 +57,7 @@ import android.os.AsyncTask; import android.os.Build; import android.os.Bundle; import android.os.Environment; import android.os.Process; import android.os.RemoteCallback; import android.provider.DeviceConfig; import android.provider.Settings; Loading Loading @@ -378,20 +379,66 @@ public class HistoricalRegistry implements HistoricalRegistryInterface { public void dump(String prefix, PrintWriter pw, int filterUid, @Nullable String filterPackage, @Nullable String filterAttributionTag, int filterOp, int filter, @NonNull SimpleDateFormat sdf, @NonNull Date date, boolean includeDiscreteOps, int limit) { int limit, boolean dumpHistory) { pw.println(); pw.print(prefix); pw.print("History:"); pw.print(" mode="); pw.println(AppOpsManager.historicalModeToString(mMode)); long shortIntervalMinute = Duration.ofMillis(mShortIntervalQuantizationMillis).toMinutes(); long longIntervalMinute = Duration.ofMillis(mLongIntervalQuantizationMillis).toMinutes(); pw.print("SHORT_INTERVAL(Aggregation Bucket)="); pw.print(shortIntervalMinute + " Minute"); pw.print(", LONG_INTERVAL(Aggregation Bucket)="); pw.println(longIntervalMinute + " Minutes"); pw.print("Database size(bytes): SHORT_INTERVAL="); pw.print(getDatabaseFile(SHORT_INTERVAL_DATABASE_FILE).length()); pw.print(", LONG_INTERVAL="); pw.println(getDatabaseFile(LONG_INTERVAL_DATABASE_FILE).length()); pw.print("Database Total records: SHORT_INTERVAL="); pw.print(mShortIntervalHistoryHelper.getTotalRecordsCount()); pw.print(", LONG_INTERVAL="); pw.println(mLongIntervalHistoryHelper.getTotalRecordsCount()); IntArray opCodes = new IntArray(); long endTimeMillis = System.currentTimeMillis(); if (!dumpHistory && !includeDiscreteOps) { filter = AppOpsManager.FILTER_BY_OP_NAMES; // print privacy indicator records for last 1 hour (or up to 500 records) long beginTimeMillis = endTimeMillis - Duration.ofHours(1).toMillis(); opCodes.add(OP_CAMERA); opCodes.add(OP_PHONE_CALL_CAMERA); opCodes.add(OP_RECORD_AUDIO); opCodes.add(OP_PHONE_CALL_MICROPHONE); opCodes.add(OP_RECEIVE_AMBIENT_TRIGGER_AUDIO); opCodes.add(OP_RECEIVE_SANDBOX_TRIGGER_AUDIO); opCodes.add(OP_FINE_LOCATION); opCodes.add(OP_COARSE_LOCATION); opCodes.add(OP_EMERGENCY_LOCATION); pw.println("----Location, Microphone, and Camera App Ops (Last 1 Hour)----"); mShortIntervalHistoryHelper.dump(beginTimeMillis, endTimeMillis, pw, Process.INVALID_UID, null, null, opCodes, filter, sdf, date, 500); return; } if ((filter & AppOpsManager.FILTER_BY_OP_NAMES) != 0 && filterOp != AppOpsManager.OP_NONE) { opCodes.add(filterOp); } long beginTimeMillis = endTimeMillis - mHistoryRetentionMillis; if (includeDiscreteOps) { pw.println("------------Discrete App Ops-------------"); mShortIntervalHistoryHelper.dump(pw, filterUid, filterPackage, filterAttributionTag, filterOp, filter, sdf, date, limit); mShortIntervalHistoryHelper.dump(beginTimeMillis, endTimeMillis, pw, filterUid, filterPackage, filterAttributionTag, opCodes, filter, sdf, date, limit); } else { pw.println("------------Aggregated App Ops-------------"); mLongIntervalHistoryHelper.dump(pw, filterUid, filterPackage, filterAttributionTag, filterOp, filter, sdf, date, limit); mLongIntervalHistoryHelper.dump(beginTimeMillis, endTimeMillis, pw, filterUid, filterPackage, filterAttributionTag, opCodes, filter, sdf, date, limit); } } Loading