Loading core/java/android/provider/DeviceConfig.java +1 −1 Original line number Original line Diff line number Diff line Loading @@ -646,7 +646,7 @@ public final class DeviceConfig { * @param name The name of the property to look up. * @param name The name of the property to look up. * @param defaultValue The value to return if the property does not exist or has no non-null * @param defaultValue The value to return if the property does not exist or has no non-null * value. * value. * @return the corresponding value, or defaultValue if none exists. * @return the correspondfing value, or defaultValue if none exists. * @hide * @hide */ */ @SystemApi @SystemApi Loading services/core/java/com/android/server/appop/DiscreteRegistry.java +70 −11 Original line number Original line Diff line number Diff line Loading @@ -31,14 +31,18 @@ import static android.app.AppOpsManager.OP_RECORD_AUDIO; import static android.app.AppOpsManager.flagsToString; import static android.app.AppOpsManager.flagsToString; import static android.app.AppOpsManager.getUidStateName; import static android.app.AppOpsManager.getUidStateName; import static java.lang.Long.min; import static java.lang.Math.max; import static java.lang.Math.max; import android.annotation.NonNull; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.Nullable; import android.app.AppOpsManager; import android.app.AppOpsManager; import android.os.AsyncTask; import android.os.Build; import android.os.Environment; import android.os.Environment; import android.os.FileUtils; import android.os.FileUtils; import android.os.Process; import android.os.Process; import android.provider.DeviceConfig; import android.util.ArrayMap; import android.util.ArrayMap; import android.util.Slog; import android.util.Slog; import android.util.TypedXmlPullParser; import android.util.TypedXmlPullParser; Loading Loading @@ -82,8 +86,16 @@ final class DiscreteRegistry { static final String TIMELINE_FILE_SUFFIX = "tl"; static final String TIMELINE_FILE_SUFFIX = "tl"; private static final String TAG = DiscreteRegistry.class.getSimpleName(); private static final String TAG = DiscreteRegistry.class.getSimpleName(); private static final long TIMELINE_HISTORY_CUTOFF = Duration.ofHours(24).toMillis(); private static final String PROPERTY_DISCRETE_HISTORY_CUTOFF = "discrete_history_cutoff_millis"; private static final long TIMELINE_QUANTIZATION = Duration.ofMinutes(1).toMillis(); private static final String PROPERTY_DISCRETE_HISTORY_QUANTIZATION = "discrete_history_quantization_millis"; 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 = Duration.ofMinutes(1).toMillis(); private static long sDiscreteHistoryCutoff; private static long sDiscreteHistoryQuantization; private static final String TAG_HISTORY = "h"; private static final String TAG_HISTORY = "h"; private static final String ATTR_VERSION = "v"; private static final String ATTR_VERSION = "v"; Loading Loading @@ -116,7 +128,7 @@ final class DiscreteRegistry { private final @NonNull Object mInMemoryLock; private final @NonNull Object mInMemoryLock; @GuardedBy("mOnDiskLock") @GuardedBy("mOnDiskLock") private final File mDiscreteAccessDir; private File mDiscreteAccessDir; @GuardedBy("mInMemoryLock") @GuardedBy("mInMemoryLock") private DiscreteOps mDiscreteOps; private DiscreteOps mDiscreteOps; Loading @@ -126,11 +138,43 @@ final class DiscreteRegistry { DiscreteRegistry(Object inMemoryLock) { DiscreteRegistry(Object inMemoryLock) { mInMemoryLock = inMemoryLock; mInMemoryLock = inMemoryLock; } void systemReady() { synchronized (mOnDiskLock) { mDiscreteAccessDir = new File(new File(Environment.getDataSystemDirectory(), "appops"), mDiscreteAccessDir = new File(new File(Environment.getDataSystemDirectory(), "appops"), "discrete"); "discrete"); createDiscreteAccessDir(); createDiscreteAccessDirLocked(); mDiscreteOps = new DiscreteOps(); mDiscreteOps = new DiscreteOps(); } } DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_PRIVACY, 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); } 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) { sDiscreteHistoryCutoff = min(MAXIMUM_DISCRETE_HISTORY_CUTOFF, sDiscreteHistoryCutoff); } } if (p.getKeyset().contains(PROPERTY_DISCRETE_HISTORY_QUANTIZATION)) { sDiscreteHistoryQuantization = p.getLong(PROPERTY_DISCRETE_HISTORY_QUANTIZATION, DEFAULT_DISCRETE_HISTORY_QUANTIZATION); if (!Build.IS_DEBUGGABLE) { sDiscreteHistoryQuantization = max(DEFAULT_DISCRETE_HISTORY_QUANTIZATION, sDiscreteHistoryQuantization); } } } private void createDiscreteAccessDir() { private void createDiscreteAccessDir() { if (!mDiscreteAccessDir.exists()) { if (!mDiscreteAccessDir.exists()) { Loading @@ -142,6 +186,7 @@ final class DiscreteRegistry { } } } } /* can be called only after HistoricalRegistry.isPersistenceInitialized() check */ void recordDiscreteAccess(int uid, String packageName, int op, @Nullable String attributionTag, void recordDiscreteAccess(int uid, String packageName, int op, @Nullable String attributionTag, @AppOpsManager.OpFlags int flags, @AppOpsManager.UidState int uidState, long accessTime, @AppOpsManager.OpFlags int flags, @AppOpsManager.UidState int uidState, long accessTime, long accessDuration) { long accessDuration) { Loading @@ -156,6 +201,10 @@ final class DiscreteRegistry { void writeAndClearAccessHistory() { void writeAndClearAccessHistory() { synchronized (mOnDiskLock) { synchronized (mOnDiskLock) { if (mDiscreteAccessDir == null) { Slog.e(TAG, "State not saved - persistence not initialized."); return; } final File[] files = mDiscreteAccessDir.listFiles(); final File[] files = mDiscreteAccessDir.listFiles(); if (files != null && files.length > 0) { if (files != null && files.length > 0) { for (File f : files) { for (File f : files) { Loading @@ -166,7 +215,7 @@ final class DiscreteRegistry { try { try { long timestamp = Long.valueOf(fileName.substring(0, long timestamp = Long.valueOf(fileName.substring(0, fileName.length() - TIMELINE_FILE_SUFFIX.length())); fileName.length() - TIMELINE_FILE_SUFFIX.length())); if (Instant.now().minus(TIMELINE_HISTORY_CUTOFF, if (Instant.now().minus(sDiscreteHistoryCutoff, ChronoUnit.MILLIS).toEpochMilli() > timestamp) { ChronoUnit.MILLIS).toEpochMilli() > timestamp) { f.delete(); f.delete(); Slog.e(TAG, "Deleting file " + fileName); Slog.e(TAG, "Deleting file " + fileName); Loading Loading @@ -229,7 +278,7 @@ final class DiscreteRegistry { private void readDiscreteOpsFromDisk(DiscreteOps discreteOps) { private void readDiscreteOpsFromDisk(DiscreteOps discreteOps) { synchronized (mOnDiskLock) { synchronized (mOnDiskLock) { long beginTimeMillis = Instant.now().minus(TIMELINE_HISTORY_CUTOFF, long beginTimeMillis = Instant.now().minus(sDiscreteHistoryCutoff, ChronoUnit.MILLIS).toEpochMilli(); ChronoUnit.MILLIS).toEpochMilli(); final File[] files = mDiscreteAccessDir.listFiles(); final File[] files = mDiscreteAccessDir.listFiles(); Loading Loading @@ -423,6 +472,16 @@ final class DiscreteRegistry { } } } } private void createDiscreteAccessDirLocked() { if (!mDiscreteAccessDir.exists()) { if (!mDiscreteAccessDir.mkdirs()) { Slog.e(TAG, "Failed to create DiscreteRegistry directory"); } FileUtils.setPermissions(mDiscreteAccessDir.getPath(), FileUtils.S_IRWXU | FileUtils.S_IRWXG | FileUtils.S_IXOTH, -1, -1); } } private final class DiscreteUidOps { private final class DiscreteUidOps { ArrayMap<String, DiscretePackageOps> mPackages; ArrayMap<String, DiscretePackageOps> mPackages; Loading Loading @@ -663,7 +722,7 @@ final class DiscreteRegistry { long accessTime, long accessDuration) { long accessTime, long accessDuration) { List<DiscreteOpEvent> attributedOps = getOrCreateDiscreteOpEventsList( List<DiscreteOpEvent> attributedOps = getOrCreateDiscreteOpEventsList( attributionTag); attributionTag); accessTime = accessTime / TIMELINE_QUANTIZATION * TIMELINE_QUANTIZATION; accessTime = accessTime / sDiscreteHistoryQuantization * sDiscreteHistoryQuantization; int nAttributedOps = attributedOps.size(); int nAttributedOps = attributedOps.size(); int i = nAttributedOps; int i = nAttributedOps; Loading @@ -674,7 +733,7 @@ final class DiscreteRegistry { } } if (previousOp.mOpFlag == flags && previousOp.mUidState == uidState) { if (previousOp.mOpFlag == flags && previousOp.mUidState == uidState) { if (accessDuration != previousOp.mNoteDuration if (accessDuration != previousOp.mNoteDuration && accessDuration > TIMELINE_QUANTIZATION) { && accessDuration > sDiscreteHistoryQuantization) { break; break; } else { } else { return; return; Loading services/core/java/com/android/server/appop/HistoricalRegistry.java +1 −0 Original line number Original line Diff line number Diff line Loading @@ -246,6 +246,7 @@ final class HistoricalRegistry { + " by which to push history on next write"); + " by which to push history on next write"); } } } } mDiscreteRegistry.systemReady(); } } } } } } Loading Loading
core/java/android/provider/DeviceConfig.java +1 −1 Original line number Original line Diff line number Diff line Loading @@ -646,7 +646,7 @@ public final class DeviceConfig { * @param name The name of the property to look up. * @param name The name of the property to look up. * @param defaultValue The value to return if the property does not exist or has no non-null * @param defaultValue The value to return if the property does not exist or has no non-null * value. * value. * @return the corresponding value, or defaultValue if none exists. * @return the correspondfing value, or defaultValue if none exists. * @hide * @hide */ */ @SystemApi @SystemApi Loading
services/core/java/com/android/server/appop/DiscreteRegistry.java +70 −11 Original line number Original line Diff line number Diff line Loading @@ -31,14 +31,18 @@ import static android.app.AppOpsManager.OP_RECORD_AUDIO; import static android.app.AppOpsManager.flagsToString; import static android.app.AppOpsManager.flagsToString; import static android.app.AppOpsManager.getUidStateName; import static android.app.AppOpsManager.getUidStateName; import static java.lang.Long.min; import static java.lang.Math.max; import static java.lang.Math.max; import android.annotation.NonNull; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.Nullable; import android.app.AppOpsManager; import android.app.AppOpsManager; import android.os.AsyncTask; import android.os.Build; import android.os.Environment; import android.os.Environment; import android.os.FileUtils; import android.os.FileUtils; import android.os.Process; import android.os.Process; import android.provider.DeviceConfig; import android.util.ArrayMap; import android.util.ArrayMap; import android.util.Slog; import android.util.Slog; import android.util.TypedXmlPullParser; import android.util.TypedXmlPullParser; Loading Loading @@ -82,8 +86,16 @@ final class DiscreteRegistry { static final String TIMELINE_FILE_SUFFIX = "tl"; static final String TIMELINE_FILE_SUFFIX = "tl"; private static final String TAG = DiscreteRegistry.class.getSimpleName(); private static final String TAG = DiscreteRegistry.class.getSimpleName(); private static final long TIMELINE_HISTORY_CUTOFF = Duration.ofHours(24).toMillis(); private static final String PROPERTY_DISCRETE_HISTORY_CUTOFF = "discrete_history_cutoff_millis"; private static final long TIMELINE_QUANTIZATION = Duration.ofMinutes(1).toMillis(); private static final String PROPERTY_DISCRETE_HISTORY_QUANTIZATION = "discrete_history_quantization_millis"; 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 = Duration.ofMinutes(1).toMillis(); private static long sDiscreteHistoryCutoff; private static long sDiscreteHistoryQuantization; private static final String TAG_HISTORY = "h"; private static final String TAG_HISTORY = "h"; private static final String ATTR_VERSION = "v"; private static final String ATTR_VERSION = "v"; Loading Loading @@ -116,7 +128,7 @@ final class DiscreteRegistry { private final @NonNull Object mInMemoryLock; private final @NonNull Object mInMemoryLock; @GuardedBy("mOnDiskLock") @GuardedBy("mOnDiskLock") private final File mDiscreteAccessDir; private File mDiscreteAccessDir; @GuardedBy("mInMemoryLock") @GuardedBy("mInMemoryLock") private DiscreteOps mDiscreteOps; private DiscreteOps mDiscreteOps; Loading @@ -126,11 +138,43 @@ final class DiscreteRegistry { DiscreteRegistry(Object inMemoryLock) { DiscreteRegistry(Object inMemoryLock) { mInMemoryLock = inMemoryLock; mInMemoryLock = inMemoryLock; } void systemReady() { synchronized (mOnDiskLock) { mDiscreteAccessDir = new File(new File(Environment.getDataSystemDirectory(), "appops"), mDiscreteAccessDir = new File(new File(Environment.getDataSystemDirectory(), "appops"), "discrete"); "discrete"); createDiscreteAccessDir(); createDiscreteAccessDirLocked(); mDiscreteOps = new DiscreteOps(); mDiscreteOps = new DiscreteOps(); } } DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_PRIVACY, 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); } 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) { sDiscreteHistoryCutoff = min(MAXIMUM_DISCRETE_HISTORY_CUTOFF, sDiscreteHistoryCutoff); } } if (p.getKeyset().contains(PROPERTY_DISCRETE_HISTORY_QUANTIZATION)) { sDiscreteHistoryQuantization = p.getLong(PROPERTY_DISCRETE_HISTORY_QUANTIZATION, DEFAULT_DISCRETE_HISTORY_QUANTIZATION); if (!Build.IS_DEBUGGABLE) { sDiscreteHistoryQuantization = max(DEFAULT_DISCRETE_HISTORY_QUANTIZATION, sDiscreteHistoryQuantization); } } } private void createDiscreteAccessDir() { private void createDiscreteAccessDir() { if (!mDiscreteAccessDir.exists()) { if (!mDiscreteAccessDir.exists()) { Loading @@ -142,6 +186,7 @@ final class DiscreteRegistry { } } } } /* can be called only after HistoricalRegistry.isPersistenceInitialized() check */ void recordDiscreteAccess(int uid, String packageName, int op, @Nullable String attributionTag, void recordDiscreteAccess(int uid, String packageName, int op, @Nullable String attributionTag, @AppOpsManager.OpFlags int flags, @AppOpsManager.UidState int uidState, long accessTime, @AppOpsManager.OpFlags int flags, @AppOpsManager.UidState int uidState, long accessTime, long accessDuration) { long accessDuration) { Loading @@ -156,6 +201,10 @@ final class DiscreteRegistry { void writeAndClearAccessHistory() { void writeAndClearAccessHistory() { synchronized (mOnDiskLock) { synchronized (mOnDiskLock) { if (mDiscreteAccessDir == null) { Slog.e(TAG, "State not saved - persistence not initialized."); return; } final File[] files = mDiscreteAccessDir.listFiles(); final File[] files = mDiscreteAccessDir.listFiles(); if (files != null && files.length > 0) { if (files != null && files.length > 0) { for (File f : files) { for (File f : files) { Loading @@ -166,7 +215,7 @@ final class DiscreteRegistry { try { try { long timestamp = Long.valueOf(fileName.substring(0, long timestamp = Long.valueOf(fileName.substring(0, fileName.length() - TIMELINE_FILE_SUFFIX.length())); fileName.length() - TIMELINE_FILE_SUFFIX.length())); if (Instant.now().minus(TIMELINE_HISTORY_CUTOFF, if (Instant.now().minus(sDiscreteHistoryCutoff, ChronoUnit.MILLIS).toEpochMilli() > timestamp) { ChronoUnit.MILLIS).toEpochMilli() > timestamp) { f.delete(); f.delete(); Slog.e(TAG, "Deleting file " + fileName); Slog.e(TAG, "Deleting file " + fileName); Loading Loading @@ -229,7 +278,7 @@ final class DiscreteRegistry { private void readDiscreteOpsFromDisk(DiscreteOps discreteOps) { private void readDiscreteOpsFromDisk(DiscreteOps discreteOps) { synchronized (mOnDiskLock) { synchronized (mOnDiskLock) { long beginTimeMillis = Instant.now().minus(TIMELINE_HISTORY_CUTOFF, long beginTimeMillis = Instant.now().minus(sDiscreteHistoryCutoff, ChronoUnit.MILLIS).toEpochMilli(); ChronoUnit.MILLIS).toEpochMilli(); final File[] files = mDiscreteAccessDir.listFiles(); final File[] files = mDiscreteAccessDir.listFiles(); Loading Loading @@ -423,6 +472,16 @@ final class DiscreteRegistry { } } } } private void createDiscreteAccessDirLocked() { if (!mDiscreteAccessDir.exists()) { if (!mDiscreteAccessDir.mkdirs()) { Slog.e(TAG, "Failed to create DiscreteRegistry directory"); } FileUtils.setPermissions(mDiscreteAccessDir.getPath(), FileUtils.S_IRWXU | FileUtils.S_IRWXG | FileUtils.S_IXOTH, -1, -1); } } private final class DiscreteUidOps { private final class DiscreteUidOps { ArrayMap<String, DiscretePackageOps> mPackages; ArrayMap<String, DiscretePackageOps> mPackages; Loading Loading @@ -663,7 +722,7 @@ final class DiscreteRegistry { long accessTime, long accessDuration) { long accessTime, long accessDuration) { List<DiscreteOpEvent> attributedOps = getOrCreateDiscreteOpEventsList( List<DiscreteOpEvent> attributedOps = getOrCreateDiscreteOpEventsList( attributionTag); attributionTag); accessTime = accessTime / TIMELINE_QUANTIZATION * TIMELINE_QUANTIZATION; accessTime = accessTime / sDiscreteHistoryQuantization * sDiscreteHistoryQuantization; int nAttributedOps = attributedOps.size(); int nAttributedOps = attributedOps.size(); int i = nAttributedOps; int i = nAttributedOps; Loading @@ -674,7 +733,7 @@ final class DiscreteRegistry { } } if (previousOp.mOpFlag == flags && previousOp.mUidState == uidState) { if (previousOp.mOpFlag == flags && previousOp.mUidState == uidState) { if (accessDuration != previousOp.mNoteDuration if (accessDuration != previousOp.mNoteDuration && accessDuration > TIMELINE_QUANTIZATION) { && accessDuration > sDiscreteHistoryQuantization) { break; break; } else { } else { return; return; Loading
services/core/java/com/android/server/appop/HistoricalRegistry.java +1 −0 Original line number Original line Diff line number Diff line Loading @@ -246,6 +246,7 @@ final class HistoricalRegistry { + " by which to push history on next write"); + " by which to push history on next write"); } } } } mDiscreteRegistry.systemReady(); } } } } } } Loading