Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3c46aca4 authored by Stanislav Zholnin's avatar Stanislav Zholnin
Browse files

Add device config parameters to DiscreteRegistry.

DiscreteRegistry cut off and quantization can be set using
adb shell device_config command.

Bug: 176965672
Test: in development
Change-Id: If4df5413d7c7f9bcbdcb751ac2ab772d51c1da80
parent e1f9d6c9
Loading
Loading
Loading
Loading
+1 −1
Original line number Original line Diff line number Diff line
@@ -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
+70 −11
Original line number Original line Diff line number Diff line
@@ -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;
@@ -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";
@@ -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;
@@ -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()) {
@@ -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) {
@@ -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) {
@@ -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);
@@ -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();
@@ -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;


@@ -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;
@@ -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;
+1 −0
Original line number Original line Diff line number Diff line
@@ -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();
                }
                }
            }
            }
        }
        }