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

Commit a2eb48a8 authored by mrulhania's avatar mrulhania
Browse files

Minimize writes when reading app op events

We write the app op events from cache to database
to simplify and support versatile sql queries.

This change will minimize writes to the database
by only writing records for reqeusted app ops. This
helps in optimizing storage as we avoid writing
duplicate/premature app op events to storage.

Bug: 377584611
Flag: EXEMPT bug fix
Test: run all appops test locally via atest
Change-Id: I58467a3072690434e288ca598a552351b6a906ca
parent ef9bbd0d
Loading
Loading
Loading
Loading
+38 −13
Original line number Diff line number Diff line
@@ -118,7 +118,7 @@ public class DiscreteOpsSqlRegistry extends DiscreteOpsRegistry {
    @Override
    void shutdown() {
        mSqliteWriteHandler.removeAllPendingMessages();
        mDiscreteOpsDbHelper.insertDiscreteOps(mDiscreteOpCache.getAllEventsAndClear());
        mDiscreteOpsDbHelper.insertDiscreteOps(mDiscreteOpCache.evictAllAppOpEvents());
    }

    @Override
@@ -172,10 +172,14 @@ public class DiscreteOpsSqlRegistry extends DiscreteOpsRegistry {
            @Nullable String[] opNamesFilter,
            @Nullable String attributionTagFilter, int opFlagsFilter,
            Set<String> attributionExemptPkgs) {
        IntArray opCodes = getAppOpCodes(filter, opNamesFilter);
        // flush the cache into database before read.
        mDiscreteOpsDbHelper.insertDiscreteOps(mDiscreteOpCache.getAllEventsAndClear());
        if (opCodes != null) {
            mDiscreteOpsDbHelper.insertDiscreteOps(mDiscreteOpCache.evictAppOpEvents(opCodes));
        } else {
            mDiscreteOpsDbHelper.insertDiscreteOps(mDiscreteOpCache.evictAllAppOpEvents());
        }
        boolean assembleChains = attributionExemptPkgs != null;
        IntArray opCodes = getAppOpCodes(filter, opNamesFilter);
        beginTimeMillis = Math.max(beginTimeMillis, Instant.now().minus(sDiscreteHistoryCutoff,
                ChronoUnit.MILLIS).toEpochMilli());
        List<DiscreteOp> discreteOps = mDiscreteOpsDbHelper.getDiscreteOps(filter, uidFilter,
@@ -214,7 +218,7 @@ public class DiscreteOpsSqlRegistry extends DiscreteOpsRegistry {
            @NonNull SimpleDateFormat sdf, @NonNull Date date, @NonNull String prefix,
            int nDiscreteOps) {
        // flush the cache into database before dump.
        mDiscreteOpsDbHelper.insertDiscreteOps(mDiscreteOpCache.getAllEventsAndClear());
        mDiscreteOpsDbHelper.insertDiscreteOps(mDiscreteOpCache.evictAllAppOpEvents());
        IntArray opCodes = new IntArray();
        if (dumpOp != AppOpsManager.OP_NONE) {
            opCodes.add(dumpOp);
@@ -366,7 +370,7 @@ public class DiscreteOpsSqlRegistry extends DiscreteOpsRegistry {
                    try {
                        List<DiscreteOp> evictedEvents;
                        synchronized (mDiscreteOpCache) {
                            evictedEvents = mDiscreteOpCache.evict();
                            evictedEvents = mDiscreteOpCache.evictOldAppOpEvents();
                        }
                        mDiscreteOpsDbHelper.insertDiscreteOps(evictedEvents);
                    } finally {
@@ -389,7 +393,7 @@ public class DiscreteOpsSqlRegistry extends DiscreteOpsRegistry {
                    try {
                        List<DiscreteOp> evictedEvents;
                        synchronized (mDiscreteOpCache) {
                            evictedEvents = mDiscreteOpCache.evict();
                            evictedEvents = mDiscreteOpCache.evictOldAppOpEvents();
                            // if nothing to evict, just write the whole cache to database.
                            if (evictedEvents.isEmpty()
                                    && mDiscreteOpCache.size() >= mDiscreteOpCache.capacity()) {
@@ -451,9 +455,10 @@ public class DiscreteOpsSqlRegistry extends DiscreteOpsRegistry {
        }

        /**
         * Evict entries older than {@link DiscreteOpsRegistry#sDiscreteHistoryQuantization}.
         * Evict entries older than {@link DiscreteOpsRegistry#sDiscreteHistoryQuantization} i.e.
         * app op events older than one minute (default quantization) will be evicted.
         */
        private List<DiscreteOp> evict() {
        private List<DiscreteOp> evictOldAppOpEvents() {
            synchronized (this) {
                List<DiscreteOp> evictedEvents = new ArrayList<>();
                Set<DiscreteOp> snapshot = new ArraySet<>(mCache);
@@ -470,11 +475,9 @@ public class DiscreteOpsSqlRegistry extends DiscreteOpsRegistry {
        }

        /**
         * Remove all the entries from cache.
         *
         * @return return all removed entries.
         * Evict all app op entries from cache, and return the list of removed ops.
         */
        public List<DiscreteOp> getAllEventsAndClear() {
        public List<DiscreteOp> evictAllAppOpEvents() {
            synchronized (this) {
                List<DiscreteOp> cachedOps = new ArrayList<>(mCache.size());
                if (mCache.isEmpty()) {
@@ -486,6 +489,25 @@ public class DiscreteOpsSqlRegistry extends DiscreteOpsRegistry {
            }
        }

        /**
         * Evict specified app ops from cache, and return the list of evicted ops.
         */
        public List<DiscreteOp> evictAppOpEvents(IntArray ops) {
            synchronized (this) {
                List<DiscreteOp> evictedOps = new ArrayList<>();
                if (mCache.isEmpty()) {
                    return evictedOps;
                }
                for (DiscreteOp discreteOp: mCache) {
                    if (ops.contains(discreteOp.getOpCode())) {
                        evictedOps.add(discreteOp);
                    }
                }
                evictedOps.forEach(mCache::remove);
                return evictedOps;
            }
        }

        int size() {
            return mCache.size();
        }
@@ -646,7 +668,10 @@ public class DiscreteOpsSqlRegistry extends DiscreteOpsRegistry {
                    + ", uidState=" + getUidStateName(mUidState)
                    + ", chainId=" + mChainId
                    + ", accessTime=" + mAccessTime
                    + ", duration=" + mDuration + '}';
                    + ", mDiscretizedAccessTime=" + mDiscretizedAccessTime
                    + ", duration=" + mDuration
                    + ", mDiscretizedDuration=" + mDiscretizedDuration
                    + '}';
        }

        public int getUid() {
+2 −1
Original line number Diff line number Diff line
@@ -97,7 +97,8 @@ public class DiscreteAppOpSqlPersistenceTest {
        mDiscreteRegistry.recordDiscreteAccess(opEvent2);
        List<DiscreteOp> discreteOps = mDiscreteRegistry.getAllDiscreteOps();

        assertThat(discreteOps.size()).isEqualTo(1);
        assertWithMessage("Expected list size is 1, but the list is: " + discreteOps)
                .that(discreteOps.size()).isEqualTo(1);
        assertThat(discreteOps).contains(opEvent);
    }