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

Commit f0927919 authored by Soonil Nagarkar's avatar Soonil Nagarkar
Browse files

Refactor LocalEventLog for safety and split locations log

Locations being received and delivered are much spammier operations than
most other location logs. Split these into a separate log so they do not
overwrite other events, and output the combined log.

Test: manual
Change-Id: I86561f46d6b84307d4849b3dd455a5e56f8bc8f3
parent 6489e997
Loading
Loading
Loading
Loading
+74 −16
Original line number Diff line number Diff line
@@ -21,26 +21,23 @@ import static java.lang.Integer.bitCount;
import android.annotation.Nullable;

import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.Preconditions;

import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.ConcurrentModificationException;
import java.util.NoSuchElementException;
import java.util.Objects;

/**
 * An in-memory event log to support historical event information. The log is of a constant size,
 * and new events will overwrite old events as the log fills up.
 *
 * @param <T> log event type
 */
public class LocalEventLog<T> {

    /**
     * Consumer of log events for iterating over the log.
     *
     * @param <T> log event type
     */
    /** Consumer of log events for iterating over the log. */
    public interface LogConsumer<T> {
        /** Invoked with a time and a logEvent. */
        void acceptLog(long time, T logEvent);
@@ -54,6 +51,7 @@ public class LocalEventLog<T> {
    private static final int IS_FILLER_OFFSET = countTrailingZeros(IS_FILLER_MASK);
    private static final int TIME_DELTA_OFFSET = countTrailingZeros(TIME_DELTA_MASK);

    @VisibleForTesting
    static final int MAX_TIME_DELTA = (1 << bitCount(TIME_DELTA_MASK)) - 1;

    private static int countTrailingZeros(int i) {
@@ -79,7 +77,7 @@ public class LocalEventLog<T> {
        return (entry & IS_FILLER_MASK) != 0;
    }

    // circular buffer of log entries and events. each entry corrosponds to the log event at the
    // circular buffer of log entries and events. each entry corresponds to the log event at the
    // same index. the log entry holds the filler status and time delta according to the bit masks
    // above, and the log event is the log event.

@@ -103,6 +101,9 @@ public class LocalEventLog<T> {
    @GuardedBy("this")
    long mLastLogTime;

    @GuardedBy("this")
    long mModificationCount;

    @SuppressWarnings("unchecked")
    public LocalEventLog(int size, Class<T> clazz) {
        Preconditions.checkArgument(size > 0);
@@ -143,6 +144,7 @@ public class LocalEventLog<T> {
        if (isEmpty()) {
            mStartTime = time;
            mLastLogTime = mStartTime;
            mModificationCount++;
        }

        addLogEventInternal(false, (int) delta, logEvent);
@@ -156,6 +158,7 @@ public class LocalEventLog<T> {
        if (mLogSize == mEntries.length) {
            // if log is full, size will remain the same, but update the start time
            mStartTime += getTimeDelta(mEntries[startIndex()]);
            mModificationCount++;
        } else {
            // otherwise add an item
            mLogSize++;
@@ -170,11 +173,12 @@ public class LocalEventLog<T> {

    /** Clears the log of all entries. */
    public synchronized void clear() {
        // clear entries to allow gc
        // clear entries to aid gc
        Arrays.fill(mLogEvents, null);

        mLogEndIndex = 0;
        mLogSize = 0;
        mModificationCount++;

        mStartTime = -1;
        mLastLogTime = -1;
@@ -186,7 +190,10 @@ public class LocalEventLog<T> {
        return mLogSize == 0;
    }

    /** Iterates over the event log, passing each log string to the given consumer. */
    /**
     * Iterates over the event log, passing each log event to the given consumer. Locks the log
     * while executing so that {@link ConcurrentModificationException}s cannot occur.
     */
    public synchronized void iterate(LogConsumer<? super T> consumer) {
        LogIterator it = new LogIterator();
        while (it.hasNext()) {
@@ -195,15 +202,53 @@ public class LocalEventLog<T> {
        }
    }

    /**
     * Iterates over all the given event logs in time order, passing each log event to the given
     * consumer. It is the caller's responsibility to ensure that {@link
     * ConcurrentModificationException}s cannot occur, whether through locking or other means.
     */
    @SafeVarargs
    public static <T> void iterate(LogConsumer<? super T> consumer, LocalEventLog<T>... logs) {
        ArrayList<LocalEventLog<T>.LogIterator> its = new ArrayList<>(logs.length);
        for (LocalEventLog<T> log : logs) {
            LocalEventLog<T>.LogIterator it = log.new LogIterator();
            if (it.hasNext()) {
                its.add(it);
                it.next();
            }
        }

        while (true) {
            LocalEventLog<T>.LogIterator next = null;
            for (LocalEventLog<T>.LogIterator it : its) {
                if (it != null && (next == null || it.getTime() < next.getTime())) {
                    next = it;
                }
            }

            if (next == null) {
                return;
            }

            consumer.acceptLog(next.getTime(), next.getLog());

            if (next.hasNext()) {
                next.next();
            } else {
                its.remove(next);
            }
        }
    }

    // returns the index of the first element
    @GuardedBy("this")
    private int startIndex() {
    int startIndex() {
        return wrapIndex(mLogEndIndex - mLogSize);
    }

    // returns the index after this one
    @GuardedBy("this")
    private int incrementIndex(int index) {
    int incrementIndex(int index) {
        if (index == -1) {
            return startIndex();
        } else if (index >= 0) {
@@ -215,12 +260,15 @@ public class LocalEventLog<T> {

    // rolls over the given index if necessary
    @GuardedBy("this")
    private int wrapIndex(int index) {
    int wrapIndex(int index) {
        // java modulo will keep negative sign, we need to rollover
        return (index % mEntries.length + mEntries.length) % mEntries.length;
    }

    private class LogIterator {
    /** Iterator over log times and events. */
    protected final class LogIterator {

        private final long mModificationCount;

        private long mLogTime;
        private int mIndex;
@@ -229,8 +277,10 @@ public class LocalEventLog<T> {
        private long mCurrentTime;
        private T mCurrentLogEvent;

        LogIterator() {
        public LogIterator() {
            synchronized (LocalEventLog.this) {
                mModificationCount = LocalEventLog.this.mModificationCount;

                mLogTime = mStartTime;
                mIndex = -1;
                mCount = -1;
@@ -241,6 +291,7 @@ public class LocalEventLog<T> {

        public boolean hasNext() {
            synchronized (LocalEventLog.this) {
                checkModifications();
                return mCount < mLogSize;
            }
        }
@@ -277,5 +328,12 @@ public class LocalEventLog<T> {
                }
            } while (mCount < mLogSize && isFiller(mEntries[mIndex]));
        }

        @GuardedBy("LocalEventLog.this")
        private void checkModifications() {
            if (mModificationCount != LocalEventLog.this.mModificationCount) {
                throw new ConcurrentModificationException();
            }
        }
    }
}
+58 −19
Original line number Diff line number Diff line
@@ -52,16 +52,28 @@ public class LocationEventLog extends LocalEventLog<Object> {
        if (D) {
            return 600;
        } else {
            return 300;
        }
    }

    private static int getLocationsLogSize() {
        if (D) {
            return 200;
        } else {
            return 100;
        }
    }

    @GuardedBy("mAggregateStats")
    private final ArrayMap<String, ArrayMap<CallerIdentity, AggregateStats>> mAggregateStats;

    public LocationEventLog() {
    @GuardedBy("this")
    private final LocationsEventLog mLocationsLog;

    private LocationEventLog() {
        super(getLogSize(), Object.class);
        mAggregateStats = new ArrayMap<>(4);
        mLocationsLog = new LocationsEventLog(getLocationsLogSize());
    }

    /** Copies out all aggregated stats. */
@@ -95,39 +107,39 @@ public class LocationEventLog extends LocalEventLog<Object> {

    /** Logs a user switched event. */
    public void logUserSwitched(int userIdFrom, int userIdTo) {
        addLogEvent(new UserSwitchedEvent(userIdFrom, userIdTo));
        addLog(new UserSwitchedEvent(userIdFrom, userIdTo));
    }

    /** Logs a location enabled/disabled event. */
    public void logLocationEnabled(int userId, boolean enabled) {
        addLogEvent(new LocationEnabledEvent(userId, enabled));
        addLog(new LocationEnabledEvent(userId, enabled));
    }

    /** Logs a location enabled/disabled event. */
    public void logAdasLocationEnabled(int userId, boolean enabled) {
        addLogEvent(new LocationAdasEnabledEvent(userId, enabled));
        addLog(new LocationAdasEnabledEvent(userId, enabled));
    }

    /** Logs a location provider enabled/disabled event. */
    public void logProviderEnabled(String provider, int userId, boolean enabled) {
        addLogEvent(new ProviderEnabledEvent(provider, userId, enabled));
        addLog(new ProviderEnabledEvent(provider, userId, enabled));
    }

    /** Logs a location provider being replaced/unreplaced by a mock provider. */
    public void logProviderMocked(String provider, boolean mocked) {
        addLogEvent(new ProviderMockedEvent(provider, mocked));
        addLog(new ProviderMockedEvent(provider, mocked));
    }

    /** Logs a new client registration for a location provider. */
    public void logProviderClientRegistered(String provider, CallerIdentity identity,
            LocationRequest request) {
        addLogEvent(new ProviderClientRegisterEvent(provider, true, identity, request));
        addLog(new ProviderClientRegisterEvent(provider, true, identity, request));
        getAggregateStats(provider, identity).markRequestAdded(request.getIntervalMillis());
    }

    /** Logs a client unregistration for a location provider. */
    public void logProviderClientUnregistered(String provider, CallerIdentity identity) {
        addLogEvent(new ProviderClientRegisterEvent(provider, false, identity, null));
        addLog(new ProviderClientRegisterEvent(provider, false, identity, null));
        getAggregateStats(provider, identity).markRequestRemoved();
    }

@@ -144,7 +156,7 @@ public class LocationEventLog extends LocalEventLog<Object> {
    /** Logs a client for a location provider entering the foreground state. */
    public void logProviderClientForeground(String provider, CallerIdentity identity) {
        if (D) {
            addLogEvent(new ProviderClientForegroundEvent(provider, true, identity));
            addLog(new ProviderClientForegroundEvent(provider, true, identity));
        }
        getAggregateStats(provider, identity).markRequestForeground();
    }
@@ -152,7 +164,7 @@ public class LocationEventLog extends LocalEventLog<Object> {
    /** Logs a client for a location provider leaving the foreground state. */
    public void logProviderClientBackground(String provider, CallerIdentity identity) {
        if (D) {
            addLogEvent(new ProviderClientForegroundEvent(provider, false, identity));
            addLog(new ProviderClientForegroundEvent(provider, false, identity));
        }
        getAggregateStats(provider, identity).markRequestBackground();
    }
@@ -160,32 +172,34 @@ public class LocationEventLog extends LocalEventLog<Object> {
    /** Logs a client for a location provider entering the permitted state. */
    public void logProviderClientPermitted(String provider, CallerIdentity identity) {
        if (D) {
            addLogEvent(new ProviderClientPermittedEvent(provider, true, identity));
            addLog(new ProviderClientPermittedEvent(provider, true, identity));
        }
    }

    /** Logs a client for a location provider leaving the permitted state. */
    public void logProviderClientUnpermitted(String provider, CallerIdentity identity) {
        if (D) {
            addLogEvent(new ProviderClientPermittedEvent(provider, false, identity));
            addLog(new ProviderClientPermittedEvent(provider, false, identity));
        }
    }

    /** Logs a change to the provider request for a location provider. */
    public void logProviderUpdateRequest(String provider, ProviderRequest request) {
        addLogEvent(new ProviderUpdateEvent(provider, request));
        addLog(new ProviderUpdateEvent(provider, request));
    }

    /** Logs a new incoming location for a location provider. */
    public void logProviderReceivedLocations(String provider, int numLocations) {
        addLogEvent(new ProviderReceiveLocationEvent(provider, numLocations));
        synchronized (this) {
            mLocationsLog.logProviderReceivedLocations(provider, numLocations);
        }
    }

    /** Logs a location deliver for a client of a location provider. */
    public void logProviderDeliveredLocations(String provider, int numLocations,
            CallerIdentity identity) {
        if (D) {
            addLogEvent(new ProviderDeliverLocationEvent(provider, numLocations, identity));
        synchronized (this) {
            mLocationsLog.logProviderDeliveredLocations(provider, numLocations, identity);
        }
        getAggregateStats(provider, identity).markLocationDelivered();
    }
@@ -193,19 +207,24 @@ public class LocationEventLog extends LocalEventLog<Object> {
    /** Logs that a provider has entered or exited stationary throttling. */
    public void logProviderStationaryThrottled(String provider, boolean throttled,
            ProviderRequest request) {
        addLogEvent(new ProviderStationaryThrottledEvent(provider, throttled, request));
        addLog(new ProviderStationaryThrottledEvent(provider, throttled, request));
    }

    /** Logs that the location power save mode has changed. */
    public void logLocationPowerSaveMode(
            @LocationPowerSaveMode int locationPowerSaveMode) {
        addLogEvent(new LocationPowerSaveModeEvent(locationPowerSaveMode));
        addLog(new LocationPowerSaveModeEvent(locationPowerSaveMode));
    }

    private void addLogEvent(Object logEvent) {
    private void addLog(Object logEvent) {
        addLog(SystemClock.elapsedRealtime(), logEvent);
    }

    @Override
    public synchronized void iterate(LogConsumer<? super Object> consumer) {
        iterate(consumer, this, mLocationsLog);
    }

    public void iterate(Consumer<String> consumer) {
        iterate(consumer, null);
    }
@@ -488,6 +507,26 @@ public class LocationEventLog extends LocalEventLog<Object> {
        }
    }

    private static final class LocationsEventLog extends LocalEventLog<Object> {

        LocationsEventLog(int size) {
            super(size, Object.class);
        }

        public void logProviderReceivedLocations(String provider, int numLocations) {
            addLog(new ProviderReceiveLocationEvent(provider, numLocations));
        }

        public void logProviderDeliveredLocations(String provider, int numLocations,
                CallerIdentity identity) {
            addLog(new ProviderDeliverLocationEvent(provider, numLocations, identity));
        }

        private void addLog(Object logEvent) {
            this.addLog(SystemClock.elapsedRealtime(), logEvent);
        }
    }

    /**
     * Aggregate statistics for a single package under a single provider.
     */