Loading core/java/android/app/AppOpsManager.java +17 −6 Original line number Diff line number Diff line Loading @@ -6511,13 +6511,21 @@ public class AppOpsManager { NoteOpEvent note = new NoteOpEvent(discreteAccessTime, discreteAccessDuration, null); accessEvents.append(key, note); AttributedOpEntry access = new AttributedOpEntry(mOp, false, accessEvents, null); for (int i = discreteAccesses.size() - 1; i >= 0; i--) { if (discreteAccesses.get(i).getLastAccessTime(OP_FLAGS_ALL) < discreteAccessTime) { discreteAccesses.add(i + 1, access); return; int insertionPoint = discreteAccesses.size() - 1; for (; insertionPoint >= 0; insertionPoint--) { if (discreteAccesses.get(insertionPoint).getLastAccessTime(OP_FLAGS_ALL) < discreteAccessTime) { break; } } discreteAccesses.add(0, access); insertionPoint++; if (insertionPoint < discreteAccesses.size() && discreteAccesses.get( insertionPoint).getLastAccessTime(OP_FLAGS_ALL) == discreteAccessTime) { discreteAccesses.set(insertionPoint, mergeAttributedOpEntries( Arrays.asList(discreteAccesses.get(insertionPoint), access))); } else { discreteAccesses.add(insertionPoint, access); } } /** Loading Loading @@ -9858,8 +9866,11 @@ public class AppOpsManager { NoteOpEvent reject = a.getLastRejectEvent(uidState, uidState, flags); if (access != null) { NoteOpEvent existingAccess = accessEvents.get(key); if (existingAccess == null || existingAccess.getDuration() == -1) { accessEvents.append(key, access); } } if (reject != null) { rejectEvents.append(key, reject); } Loading services/core/java/com/android/server/appop/DiscreteRegistry.java +73 −22 Original line number Diff line number Diff line Loading @@ -92,8 +92,8 @@ final class DiscreteRegistry { "discrete_history_quantization_millis"; private static final String PROPERTY_DISCRETE_FLAGS = "discrete_history_op_flags"; private static final String PROPERTY_DISCRETE_OPS_LIST = "discrete_history_ops_cslist"; private static final String DEFAULT_DISCRETE_OPS = OP_CAMERA + "," + OP_RECORD_AUDIO + "," + OP_FINE_LOCATION + "," + OP_COARSE_LOCATION; private static final String DEFAULT_DISCRETE_OPS = OP_FINE_LOCATION + "," + OP_COARSE_LOCATION + "," + OP_CAMERA + "," + OP_RECORD_AUDIO; private static final long DEFAULT_DISCRETE_HISTORY_CUTOFF = Duration.ofHours(24).toMillis(); private static final long MAXIMUM_DISCRETE_HISTORY_CUTOFF = Duration.ofDays(30).toMillis(); private static final long DEFAULT_DISCRETE_HISTORY_QUANTIZATION = Loading @@ -104,7 +104,6 @@ final class DiscreteRegistry { private static int[] sDiscreteOps; private static int sDiscreteFlags; private static final String TAG_HISTORY = "h"; private static final String ATTR_VERSION = "v"; private static final int CURRENT_VERSION = 1; Loading Loading @@ -144,6 +143,8 @@ final class DiscreteRegistry { @GuardedBy("mOnDiskLock") private DiscreteOps mCachedOps = null; private boolean mDebugMode = false; DiscreteRegistry(Object inMemoryLock) { mInMemoryLock = inMemoryLock; } Loading @@ -159,40 +160,35 @@ final class DiscreteRegistry { AsyncTask.THREAD_POOL_EXECUTOR, (DeviceConfig.Properties p) -> { setDiscreteHistoryParameters(p); }); sDiscreteHistoryCutoff = DeviceConfig.getLong(DeviceConfig.NAMESPACE_PRIVACY, PROPERTY_DISCRETE_HISTORY_CUTOFF, DEFAULT_DISCRETE_HISTORY_CUTOFF); sDiscreteHistoryQuantization = DeviceConfig.getLong(DeviceConfig.NAMESPACE_PRIVACY, PROPERTY_DISCRETE_HISTORY_QUANTIZATION, DEFAULT_DISCRETE_HISTORY_QUANTIZATION); sDiscreteFlags = DeviceConfig.getInt(DeviceConfig.NAMESPACE_PRIVACY, PROPERTY_DISCRETE_FLAGS, OP_FLAGS_DISCRETE); sDiscreteOps = parseOpsList(DeviceConfig.getString(DeviceConfig.NAMESPACE_PRIVACY, PROPERTY_DISCRETE_OPS_LIST, DEFAULT_DISCRETE_OPS)); setDiscreteHistoryParameters(DeviceConfig.getProperties(DeviceConfig.NAMESPACE_PRIVACY)); } private void setDiscreteHistoryParameters(DeviceConfig.Properties p) { if (p.getKeyset().contains(PROPERTY_DISCRETE_HISTORY_CUTOFF)) { sDiscreteHistoryCutoff = p.getLong(PROPERTY_DISCRETE_HISTORY_CUTOFF, DEFAULT_DISCRETE_HISTORY_CUTOFF); if (!Build.IS_DEBUGGABLE) { if (!Build.IS_DEBUGGABLE && !mDebugMode) { sDiscreteHistoryCutoff = min(MAXIMUM_DISCRETE_HISTORY_CUTOFF, sDiscreteHistoryCutoff); } } else { sDiscreteHistoryCutoff = DEFAULT_DISCRETE_HISTORY_CUTOFF; } if (p.getKeyset().contains(PROPERTY_DISCRETE_HISTORY_QUANTIZATION)) { sDiscreteHistoryQuantization = p.getLong(PROPERTY_DISCRETE_HISTORY_QUANTIZATION, DEFAULT_DISCRETE_HISTORY_QUANTIZATION); if (!Build.IS_DEBUGGABLE) { if (!Build.IS_DEBUGGABLE && !mDebugMode) { sDiscreteHistoryQuantization = max(DEFAULT_DISCRETE_HISTORY_QUANTIZATION, sDiscreteHistoryQuantization); } } else { sDiscreteHistoryQuantization = DEFAULT_DISCRETE_HISTORY_QUANTIZATION; } if (p.getKeyset().contains(PROPERTY_DISCRETE_FLAGS)) { sDiscreteFlags = p.getInt(PROPERTY_DISCRETE_FLAGS, OP_FLAGS_DISCRETE); } if (p.getKeyset().contains(PROPERTY_DISCRETE_OPS_LIST)) { sDiscreteOps = parseOpsList(p.getString(PROPERTY_DISCRETE_OPS_LIST, DEFAULT_DISCRETE_OPS)); } sDiscreteFlags = p.getKeyset().contains(PROPERTY_DISCRETE_FLAGS) ? sDiscreteFlags = p.getInt(PROPERTY_DISCRETE_FLAGS, OP_FLAGS_DISCRETE) : OP_FLAGS_DISCRETE; sDiscreteOps = p.getKeyset().contains(PROPERTY_DISCRETE_OPS_LIST) ? parseOpsList( p.getString(PROPERTY_DISCRETE_OPS_LIST, DEFAULT_DISCRETE_OPS)) : parseOpsList( DEFAULT_DISCRETE_OPS); } void recordDiscreteAccess(int uid, String packageName, int op, @Nullable String attributionTag, Loading Loading @@ -232,6 +228,8 @@ final class DiscreteRegistry { @Nullable String packageNameFilter, @Nullable String[] opNamesFilter, @Nullable String attributionTagFilter, @AppOpsManager.OpFlags int flagsFilter) { DiscreteOps discreteOps = getAllDiscreteOps(); beginTimeMillis = max(beginTimeMillis, Instant.now().minus(sDiscreteHistoryCutoff, ChronoUnit.MILLIS).toEpochMilli()); discreteOps.filter(beginTimeMillis, endTimeMillis, filter, uidFilter, packageNameFilter, opNamesFilter, attributionTagFilter, flagsFilter); discreteOps.applyToHistoricalOps(result); Loading Loading @@ -282,6 +280,18 @@ final class DiscreteRegistry { } } void offsetHistory(long offset) { synchronized (mOnDiskLock) { DiscreteOps discreteOps; synchronized (mInMemoryLock) { discreteOps = getAllDiscreteOps(); clearHistory(); } discreteOps.offsetHistory(offset); persistDiscreteOpsLocked(discreteOps); } } void dump(@NonNull PrintWriter pw, int uidFilter, @Nullable String packageNameFilter, @Nullable String attributionTagFilter, @AppOpsManager.HistoricalOpsRequestFilter int filter, int dumpOp, Loading Loading @@ -363,6 +373,13 @@ final class DiscreteRegistry { } } private void offsetHistory(long offset) { int nUids = mUids.size(); for (int i = 0; i < nUids; i++) { mUids.valueAt(i).offsetHistory(offset); } } private void clearHistory(int uid, String packageName) { if (mUids.containsKey(uid)) { mUids.get(uid).clearPackage(packageName); Loading Loading @@ -549,6 +566,13 @@ final class DiscreteRegistry { } } private void offsetHistory(long offset) { int nPackages = mPackages.size(); for (int i = 0; i < nPackages; i++) { mPackages.valueAt(i).offsetHistory(offset); } } private void clearPackage(String packageName) { mPackages.remove(packageName); } Loading Loading @@ -656,6 +680,13 @@ final class DiscreteRegistry { } } private void offsetHistory(long offset) { int nOps = mPackageOps.size(); for (int i = 0; i < nOps; i++) { mPackageOps.valueAt(i).offsetHistory(offset); } } private DiscreteOp getOrCreateDiscreteOp(int op) { DiscreteOp result = mPackageOps.get(op); if (result == null) { Loading Loading @@ -749,12 +780,29 @@ final class DiscreteRegistry { } } private void offsetHistory(long offset) { int nTags = mAttributedOps.size(); for (int i = 0; i < nTags; i++) { List<DiscreteOpEvent> list = mAttributedOps.valueAt(i); int n = list.size(); for (int j = 0; j < n; j++) { DiscreteOpEvent event = list.get(j); list.set(j, new DiscreteOpEvent(event.mNoteTime - offset, event.mNoteDuration, event.mUidState, event.mOpFlag)); } } } void addDiscreteAccess(@Nullable String attributionTag, @AppOpsManager.OpFlags int flags, @AppOpsManager.UidState int uidState, long accessTime, long accessDuration) { List<DiscreteOpEvent> attributedOps = getOrCreateDiscreteOpEventsList( attributionTag); accessTime = accessTime / sDiscreteHistoryQuantization * sDiscreteHistoryQuantization; accessDuration = accessDuration == -1 ? -1 : (accessDuration + sDiscreteHistoryQuantization - 1) / sDiscreteHistoryQuantization * sDiscreteHistoryQuantization; int nAttributedOps = attributedOps.size(); int i = nAttributedOps; Loading @@ -764,8 +812,7 @@ final class DiscreteRegistry { break; } if (previousOp.mOpFlag == flags && previousOp.mUidState == uidState) { if (accessDuration != previousOp.mNoteDuration && accessDuration > sDiscreteHistoryQuantization) { if (accessDuration != previousOp.mNoteDuration) { break; } else { return; Loading Loading @@ -983,5 +1030,9 @@ final class DiscreteRegistry { } return true; } void setDebugMode(boolean debugMode) { this.mDebugMode = debugMode; } } services/core/java/com/android/server/appop/HistoricalRegistry.java +6 −0 Original line number Diff line number Diff line Loading @@ -553,6 +553,11 @@ final class HistoricalRegistry { if (mMode == AppOpsManager.HISTORICAL_MODE_DISABLED) { clearHistoryOnDiskDLocked(); } if (mMode == AppOpsManager.HISTORICAL_MODE_ENABLED_PASSIVE) { mDiscreteRegistry.setDebugMode(true); } else { mDiscreteRegistry.setDebugMode(false); } } if (mBaseSnapshotInterval != baseSnapshotInterval) { mBaseSnapshotInterval = baseSnapshotInterval; Loading Loading @@ -591,6 +596,7 @@ final class HistoricalRegistry { mPersistence.persistHistoricalOpsDLocked(history); } } mDiscreteRegistry.offsetHistory(offsetMillis); } void addHistoricalOps(HistoricalOps ops) { Loading Loading
core/java/android/app/AppOpsManager.java +17 −6 Original line number Diff line number Diff line Loading @@ -6511,13 +6511,21 @@ public class AppOpsManager { NoteOpEvent note = new NoteOpEvent(discreteAccessTime, discreteAccessDuration, null); accessEvents.append(key, note); AttributedOpEntry access = new AttributedOpEntry(mOp, false, accessEvents, null); for (int i = discreteAccesses.size() - 1; i >= 0; i--) { if (discreteAccesses.get(i).getLastAccessTime(OP_FLAGS_ALL) < discreteAccessTime) { discreteAccesses.add(i + 1, access); return; int insertionPoint = discreteAccesses.size() - 1; for (; insertionPoint >= 0; insertionPoint--) { if (discreteAccesses.get(insertionPoint).getLastAccessTime(OP_FLAGS_ALL) < discreteAccessTime) { break; } } discreteAccesses.add(0, access); insertionPoint++; if (insertionPoint < discreteAccesses.size() && discreteAccesses.get( insertionPoint).getLastAccessTime(OP_FLAGS_ALL) == discreteAccessTime) { discreteAccesses.set(insertionPoint, mergeAttributedOpEntries( Arrays.asList(discreteAccesses.get(insertionPoint), access))); } else { discreteAccesses.add(insertionPoint, access); } } /** Loading Loading @@ -9858,8 +9866,11 @@ public class AppOpsManager { NoteOpEvent reject = a.getLastRejectEvent(uidState, uidState, flags); if (access != null) { NoteOpEvent existingAccess = accessEvents.get(key); if (existingAccess == null || existingAccess.getDuration() == -1) { accessEvents.append(key, access); } } if (reject != null) { rejectEvents.append(key, reject); } Loading
services/core/java/com/android/server/appop/DiscreteRegistry.java +73 −22 Original line number Diff line number Diff line Loading @@ -92,8 +92,8 @@ final class DiscreteRegistry { "discrete_history_quantization_millis"; private static final String PROPERTY_DISCRETE_FLAGS = "discrete_history_op_flags"; private static final String PROPERTY_DISCRETE_OPS_LIST = "discrete_history_ops_cslist"; private static final String DEFAULT_DISCRETE_OPS = OP_CAMERA + "," + OP_RECORD_AUDIO + "," + OP_FINE_LOCATION + "," + OP_COARSE_LOCATION; private static final String DEFAULT_DISCRETE_OPS = OP_FINE_LOCATION + "," + OP_COARSE_LOCATION + "," + OP_CAMERA + "," + OP_RECORD_AUDIO; private static final long DEFAULT_DISCRETE_HISTORY_CUTOFF = Duration.ofHours(24).toMillis(); private static final long MAXIMUM_DISCRETE_HISTORY_CUTOFF = Duration.ofDays(30).toMillis(); private static final long DEFAULT_DISCRETE_HISTORY_QUANTIZATION = Loading @@ -104,7 +104,6 @@ final class DiscreteRegistry { private static int[] sDiscreteOps; private static int sDiscreteFlags; private static final String TAG_HISTORY = "h"; private static final String ATTR_VERSION = "v"; private static final int CURRENT_VERSION = 1; Loading Loading @@ -144,6 +143,8 @@ final class DiscreteRegistry { @GuardedBy("mOnDiskLock") private DiscreteOps mCachedOps = null; private boolean mDebugMode = false; DiscreteRegistry(Object inMemoryLock) { mInMemoryLock = inMemoryLock; } Loading @@ -159,40 +160,35 @@ final class DiscreteRegistry { AsyncTask.THREAD_POOL_EXECUTOR, (DeviceConfig.Properties p) -> { setDiscreteHistoryParameters(p); }); sDiscreteHistoryCutoff = DeviceConfig.getLong(DeviceConfig.NAMESPACE_PRIVACY, PROPERTY_DISCRETE_HISTORY_CUTOFF, DEFAULT_DISCRETE_HISTORY_CUTOFF); sDiscreteHistoryQuantization = DeviceConfig.getLong(DeviceConfig.NAMESPACE_PRIVACY, PROPERTY_DISCRETE_HISTORY_QUANTIZATION, DEFAULT_DISCRETE_HISTORY_QUANTIZATION); sDiscreteFlags = DeviceConfig.getInt(DeviceConfig.NAMESPACE_PRIVACY, PROPERTY_DISCRETE_FLAGS, OP_FLAGS_DISCRETE); sDiscreteOps = parseOpsList(DeviceConfig.getString(DeviceConfig.NAMESPACE_PRIVACY, PROPERTY_DISCRETE_OPS_LIST, DEFAULT_DISCRETE_OPS)); setDiscreteHistoryParameters(DeviceConfig.getProperties(DeviceConfig.NAMESPACE_PRIVACY)); } private void setDiscreteHistoryParameters(DeviceConfig.Properties p) { if (p.getKeyset().contains(PROPERTY_DISCRETE_HISTORY_CUTOFF)) { sDiscreteHistoryCutoff = p.getLong(PROPERTY_DISCRETE_HISTORY_CUTOFF, DEFAULT_DISCRETE_HISTORY_CUTOFF); if (!Build.IS_DEBUGGABLE) { if (!Build.IS_DEBUGGABLE && !mDebugMode) { sDiscreteHistoryCutoff = min(MAXIMUM_DISCRETE_HISTORY_CUTOFF, sDiscreteHistoryCutoff); } } else { sDiscreteHistoryCutoff = DEFAULT_DISCRETE_HISTORY_CUTOFF; } if (p.getKeyset().contains(PROPERTY_DISCRETE_HISTORY_QUANTIZATION)) { sDiscreteHistoryQuantization = p.getLong(PROPERTY_DISCRETE_HISTORY_QUANTIZATION, DEFAULT_DISCRETE_HISTORY_QUANTIZATION); if (!Build.IS_DEBUGGABLE) { if (!Build.IS_DEBUGGABLE && !mDebugMode) { sDiscreteHistoryQuantization = max(DEFAULT_DISCRETE_HISTORY_QUANTIZATION, sDiscreteHistoryQuantization); } } else { sDiscreteHistoryQuantization = DEFAULT_DISCRETE_HISTORY_QUANTIZATION; } if (p.getKeyset().contains(PROPERTY_DISCRETE_FLAGS)) { sDiscreteFlags = p.getInt(PROPERTY_DISCRETE_FLAGS, OP_FLAGS_DISCRETE); } if (p.getKeyset().contains(PROPERTY_DISCRETE_OPS_LIST)) { sDiscreteOps = parseOpsList(p.getString(PROPERTY_DISCRETE_OPS_LIST, DEFAULT_DISCRETE_OPS)); } sDiscreteFlags = p.getKeyset().contains(PROPERTY_DISCRETE_FLAGS) ? sDiscreteFlags = p.getInt(PROPERTY_DISCRETE_FLAGS, OP_FLAGS_DISCRETE) : OP_FLAGS_DISCRETE; sDiscreteOps = p.getKeyset().contains(PROPERTY_DISCRETE_OPS_LIST) ? parseOpsList( p.getString(PROPERTY_DISCRETE_OPS_LIST, DEFAULT_DISCRETE_OPS)) : parseOpsList( DEFAULT_DISCRETE_OPS); } void recordDiscreteAccess(int uid, String packageName, int op, @Nullable String attributionTag, Loading Loading @@ -232,6 +228,8 @@ final class DiscreteRegistry { @Nullable String packageNameFilter, @Nullable String[] opNamesFilter, @Nullable String attributionTagFilter, @AppOpsManager.OpFlags int flagsFilter) { DiscreteOps discreteOps = getAllDiscreteOps(); beginTimeMillis = max(beginTimeMillis, Instant.now().minus(sDiscreteHistoryCutoff, ChronoUnit.MILLIS).toEpochMilli()); discreteOps.filter(beginTimeMillis, endTimeMillis, filter, uidFilter, packageNameFilter, opNamesFilter, attributionTagFilter, flagsFilter); discreteOps.applyToHistoricalOps(result); Loading Loading @@ -282,6 +280,18 @@ final class DiscreteRegistry { } } void offsetHistory(long offset) { synchronized (mOnDiskLock) { DiscreteOps discreteOps; synchronized (mInMemoryLock) { discreteOps = getAllDiscreteOps(); clearHistory(); } discreteOps.offsetHistory(offset); persistDiscreteOpsLocked(discreteOps); } } void dump(@NonNull PrintWriter pw, int uidFilter, @Nullable String packageNameFilter, @Nullable String attributionTagFilter, @AppOpsManager.HistoricalOpsRequestFilter int filter, int dumpOp, Loading Loading @@ -363,6 +373,13 @@ final class DiscreteRegistry { } } private void offsetHistory(long offset) { int nUids = mUids.size(); for (int i = 0; i < nUids; i++) { mUids.valueAt(i).offsetHistory(offset); } } private void clearHistory(int uid, String packageName) { if (mUids.containsKey(uid)) { mUids.get(uid).clearPackage(packageName); Loading Loading @@ -549,6 +566,13 @@ final class DiscreteRegistry { } } private void offsetHistory(long offset) { int nPackages = mPackages.size(); for (int i = 0; i < nPackages; i++) { mPackages.valueAt(i).offsetHistory(offset); } } private void clearPackage(String packageName) { mPackages.remove(packageName); } Loading Loading @@ -656,6 +680,13 @@ final class DiscreteRegistry { } } private void offsetHistory(long offset) { int nOps = mPackageOps.size(); for (int i = 0; i < nOps; i++) { mPackageOps.valueAt(i).offsetHistory(offset); } } private DiscreteOp getOrCreateDiscreteOp(int op) { DiscreteOp result = mPackageOps.get(op); if (result == null) { Loading Loading @@ -749,12 +780,29 @@ final class DiscreteRegistry { } } private void offsetHistory(long offset) { int nTags = mAttributedOps.size(); for (int i = 0; i < nTags; i++) { List<DiscreteOpEvent> list = mAttributedOps.valueAt(i); int n = list.size(); for (int j = 0; j < n; j++) { DiscreteOpEvent event = list.get(j); list.set(j, new DiscreteOpEvent(event.mNoteTime - offset, event.mNoteDuration, event.mUidState, event.mOpFlag)); } } } void addDiscreteAccess(@Nullable String attributionTag, @AppOpsManager.OpFlags int flags, @AppOpsManager.UidState int uidState, long accessTime, long accessDuration) { List<DiscreteOpEvent> attributedOps = getOrCreateDiscreteOpEventsList( attributionTag); accessTime = accessTime / sDiscreteHistoryQuantization * sDiscreteHistoryQuantization; accessDuration = accessDuration == -1 ? -1 : (accessDuration + sDiscreteHistoryQuantization - 1) / sDiscreteHistoryQuantization * sDiscreteHistoryQuantization; int nAttributedOps = attributedOps.size(); int i = nAttributedOps; Loading @@ -764,8 +812,7 @@ final class DiscreteRegistry { break; } if (previousOp.mOpFlag == flags && previousOp.mUidState == uidState) { if (accessDuration != previousOp.mNoteDuration && accessDuration > sDiscreteHistoryQuantization) { if (accessDuration != previousOp.mNoteDuration) { break; } else { return; Loading Loading @@ -983,5 +1030,9 @@ final class DiscreteRegistry { } return true; } void setDebugMode(boolean debugMode) { this.mDebugMode = debugMode; } }
services/core/java/com/android/server/appop/HistoricalRegistry.java +6 −0 Original line number Diff line number Diff line Loading @@ -553,6 +553,11 @@ final class HistoricalRegistry { if (mMode == AppOpsManager.HISTORICAL_MODE_DISABLED) { clearHistoryOnDiskDLocked(); } if (mMode == AppOpsManager.HISTORICAL_MODE_ENABLED_PASSIVE) { mDiscreteRegistry.setDebugMode(true); } else { mDiscreteRegistry.setDebugMode(false); } } if (mBaseSnapshotInterval != baseSnapshotInterval) { mBaseSnapshotInterval = baseSnapshotInterval; Loading Loading @@ -591,6 +596,7 @@ final class HistoricalRegistry { mPersistence.persistHistoricalOpsDLocked(history); } } mDiscreteRegistry.offsetHistory(offsetMillis); } void addHistoricalOps(HistoricalOps ops) { Loading