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

Commit 877f51ae authored by Chris Wren's avatar Chris Wren Committed by Android (Google) Code Review
Browse files

Merge "remove the last of the legacy log helpers"

parents 609d12df f33926ab
Loading
Loading
Loading
Loading
+68 −17
Original line number Diff line number Diff line
@@ -16,10 +16,15 @@
package android.metrics;

import android.annotation.SystemApi;
import android.util.EventLog;
import android.util.EventLog.Event;
import android.util.Log;

import com.android.internal.logging.legacy.LegacyConversionLogger;
import com.android.internal.logging.legacy.EventLogCollector;
import com.android.internal.logging.MetricsLogger;

import java.io.IOException;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.Queue;

/**
@@ -28,41 +33,87 @@ import java.util.Queue;
 */
@SystemApi
public class MetricsReader {
    private EventLogCollector mReader;
    private Queue<LogMaker> mEventQueue;
    private Queue<LogMaker> mEventQueue = new LinkedList<>();
    private long mLastEventMs;
    private long mCheckpointMs;
    private int[] LOGTAGS = { MetricsLogger.LOGTAG };

    /** Open a new session and start reading logs.
    /**
     * Read the available logs into a new session.
     *
     * The session will contain events starting from the oldest available
     * log on the system up to the most recent at the time of this call.
     *
     * A call to {@link #checkpoint()} will cause the session to contain
     * only events that occured after that call.
     *
     * Starts reading from the oldest log not already read by this reader object.
     * On first invocation starts from the oldest available log ion the system.
     * This call will not return until the system buffer overflows the
     * specified timestamp. If the specified timestamp is 0, then the
     * call will return immediately since any logs 1970 have already been
     * overwritten (n.b. if the underlying system has the capability to
     * store many decades of system logs, this call may fail in
     * interesting ways.)
     *
     * @param horizonMs block until this timestamp is overwritten, 0 for non-blocking read.
     */
    public void read(long startMs) {
        EventLogCollector reader = EventLogCollector.getInstance();
        LegacyConversionLogger logger = new LegacyConversionLogger();
        mLastEventMs = reader.collect(logger, startMs);
        mEventQueue = logger.getEvents();
    public void read(long horizonMs) {
        ArrayList<Event> nativeEvents = new ArrayList<>();
        try {
            EventLog.readEventsOnWrapping(LOGTAGS, horizonMs, nativeEvents);
        } catch (IOException e) {
            e.printStackTrace();
        }
        mEventQueue.clear();
        for (EventLog.Event event : nativeEvents) {
            final long eventTimestampMs = event.getTimeNanos() / 1000000;
            if (eventTimestampMs > mCheckpointMs) {
                Object data = event.getData();
                Object[] objects;
                if (data instanceof Object[]) {
                    objects = (Object[]) data;
                } else {
                    // wrap scalar objects
                    objects = new Object[1];
                    objects[0] = data;
                }
                mEventQueue.add(new LogMaker(objects)
                        .setTimestamp(eventTimestampMs));
                mLastEventMs = eventTimestampMs;
            }
        }
    }

    /** Cause this session to only contain events that occur after this call. */
    public void checkpoint() {
        // read the log to find the most recent event.
        read(0L);
        // any queued event is now too old, so drop them.
        mEventQueue.clear();
        mCheckpointMs = mLastEventMs;
        mEventQueue = null;
    }

    /**
     * Rewind the session to the beginning of time and read all available logs.
     *
     * A prior call to {@link #checkpoint()} will cause the reader to ignore
     * any event with a timestamp before the time of that call.
     *
     * The underlying log buffer is live: between calls to {@link #reset()}, older
     * events may be lost from the beginning of the session, and new events may
     * appear at the end.
     */
    public void reset() {
        read(mCheckpointMs);
        read(0l);
    }

    /* Does the current log session have another entry? */
    public boolean hasNext() {
        return mEventQueue == null ? false : !mEventQueue.isEmpty();
        return !mEventQueue.isEmpty();
    }

    /* Next entry in the current log session. */
    /* Return the next entry in the current log session. */
    public LogMaker next() {
        return mEventQueue == null ? null : mEventQueue.remove();
        return mEventQueue.poll();
    }

}
+3 −0
Original line number Diff line number Diff line
@@ -29,8 +29,10 @@ import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 */
public class MetricsLogger {
    // define metric categories in frameworks/base/proto/src/metrics_constants.proto.
    // mirror changes in native version at system/core/libmetricslogger/metrics_logger.cpp

    public static final int VIEW_UNKNOWN = MetricsEvent.VIEW_UNKNOWN;
    public static final int LOGTAG = EventLogTags.SYSUI_MULTI_ACTION;

    public static void visible(Context context, int category) throws IllegalArgumentException {
        if (Build.IS_DEBUGGABLE && category == VIEW_UNKNOWN) {
@@ -125,6 +127,7 @@ public class MetricsLogger {

    /** Increment the bucket with the integer label on the histogram with the given name. */
    public static void histogram(Context context, String name, int bucket) {
        // see LogHistogram in system/core/libmetricslogger/metrics_logger.cpp
        EventLogTags.writeSysuiHistogram(name, bucket);
        EventLogTags.writeSysuiMultiAction(
                new LogMaker(MetricsEvent.RESERVED_FOR_LOGBUILDER_HISTOGRAM)
+0 −173
Original line number Diff line number Diff line
/*
 * Copyright (C) 2017 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.android.internal.logging.legacy;

import android.util.ArrayMap;
import android.util.EventLog;
import android.util.Log;

import com.android.internal.annotations.VisibleForTesting;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;

/**
 * Scan the event log for interaction metrics events.
 * @hide
 */
public class EventLogCollector {
    private static final String TAG = "EventLogCollector";

    // TODO replace this with GoogleLogTags.TRON_HEARTBEAT
    @VisibleForTesting
    static final int TRON_HEARTBEAT = 208000;

    private static EventLogCollector sInstance;

    private final ArrayMap<Integer, TagParser> mTagParsers;
    private int[] mInterestingTags;

    private LogReader mLogReader;

    private EventLogCollector() {
        mTagParsers = new ArrayMap<>();
        addParser(new PowerScreenStateParser());
        addParser(new SysuiMultiActionParser());

        mLogReader = new LogReader();
    }

    public static EventLogCollector getInstance() {
        if (sInstance == null) {
            sInstance = new EventLogCollector();
        }
        return sInstance;
    }

    @VisibleForTesting
    public void setLogReader(LogReader logReader) {
        mLogReader = logReader;
    }

    private int[] getInterestingTags() {
        if (mInterestingTags == null) {
            mInterestingTags = new int[mTagParsers.size()];
            for (int i = 0; i < mTagParsers.size(); i++) {
                mInterestingTags[i] = mTagParsers.valueAt(i).getTag();
            }
        }
        return mInterestingTags;
    }

    // I would customize ArrayMap to add put(TagParser), but ArrayMap is final.
    @VisibleForTesting
    void addParser(TagParser parser) {
        mTagParsers.put(parser.getTag(), parser);
        mInterestingTags = null;
    }

    public void collect(LegacyConversionLogger logger) {
        collect(logger, 0L);
    }

    public long collect(TronLogger logger, long lastSeenEventMs) {
        long lastEventMs = 0L;
        final boolean debug = Util.debug();

        if (debug) {
            Log.d(TAG, "Eventlog Collection");
        }
        ArrayList<Event> events = new ArrayList<>();
        try {
            mLogReader.readEvents(getInterestingTags(), events);
        } catch (IOException e) {
            e.printStackTrace();
        }
        if (debug) {
            Log.d(TAG, "read this many events: " + events.size());
        }

        for (Event event : events) {
            final long millis = event.getTimeNanos() / 1000000;
            if (millis > lastSeenEventMs) {
                final int tag = event.getTag();
                TagParser parser = mTagParsers.get(tag);
                if (parser == null) {
                    if (debug) {
                        Log.d(TAG, "unknown tag: " + tag);
                    }
                    continue;
                }
                if (debug) {
                    Log.d(TAG, "parsing tag: " + tag);
                }
                parser.parseEvent(logger, event);
                lastEventMs = Math.max(lastEventMs, millis);
            } else {
                if (debug) {
                    Log.d(TAG, "old event: " + millis + " < " + lastSeenEventMs);
                }
            }
        }
        return lastEventMs;
    }

    @VisibleForTesting
    static class Event {
        long mTimeNanos;
        int mTag;
        Object mData;

        Event(long timeNanos, int tag, Object data) {
            super();
            mTimeNanos = timeNanos;
            mTag = tag;
            mData = data;
        }

        Event(EventLog.Event event) {
            mTimeNanos = event.getTimeNanos();
            mTag = event.getTag();
            mData = event.getData();
        }

        public long getTimeNanos() {
            return mTimeNanos;
        }

        public int getTag() {
            return mTag;
        }

        public Object getData() {
            return mData;
        }
    }

    @VisibleForTesting
    static class LogReader {
        public void readEvents(int[] tags, Collection<Event> events) throws IOException {
            // Testing in Android: the Static Final Class Strikes Back!
            ArrayList<EventLog.Event> nativeEvents = new ArrayList<>();
            EventLog.readEventsOnWrapping(tags, 0L, nativeEvents);
            for (EventLog.Event nativeEvent : nativeEvents) {
                Event event = new Event(nativeEvent);
                events.add(event);
            }
        }
    }
}
+0 −101
Original line number Diff line number Diff line
/*
 * Copyright (C) 2017 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.android.internal.logging.legacy;

import android.metrics.LogMaker;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;

import java.util.HashMap;
import java.util.LinkedList;
import java.util.Queue;

/** @hide */
public class LegacyConversionLogger implements TronLogger {
    private final Queue<LogMaker> mQueue;
    private HashMap<String, Boolean> mConfig;

    public LegacyConversionLogger() {
        mQueue = new LinkedList<>();
    }

    public Queue<LogMaker> getEvents() {
        return mQueue;
    }

    @Override
    public void increment(String counterName) {
        LogMaker b = new LogMaker(MetricsEvent.RESERVED_FOR_LOGBUILDER_COUNTER)
                .setCounterName(counterName)
                .setCounterValue(1);
        mQueue.add(b);
    }

    @Override
    public void incrementBy(String counterName, int value) {
        LogMaker b = new LogMaker(MetricsEvent.RESERVED_FOR_LOGBUILDER_COUNTER)
                .setCounterName(counterName)
                .setCounterValue(value);
        mQueue.add(b);
    }

    @Override
    public void incrementIntHistogram(String counterName, int bucket) {
        LogMaker b = new LogMaker(MetricsEvent.RESERVED_FOR_LOGBUILDER_HISTOGRAM)
                .setCounterName(counterName)
                .setCounterBucket(bucket)
                .setCounterValue(1);
        mQueue.add(b);
    }

    @Override
    public void incrementLongHistogram(String counterName, long bucket) {
        LogMaker b = new LogMaker(MetricsEvent.RESERVED_FOR_LOGBUILDER_HISTOGRAM)
                .setCounterName(counterName)
                .setCounterBucket(bucket)
                .setCounterValue(1);
        mQueue.add(b);
    }

    @Override
    public LogMaker obtain() {
        return new LogMaker(MetricsEvent.VIEW_UNKNOWN);
    }

    @Override
    public void dispose(LogMaker proto) {
    }

    @Override
    public void addEvent(LogMaker proto) {
        mQueue.add(proto);
    }

    @Override
    public boolean getConfig(String configName) {
        if (mConfig != null && mConfig.containsKey(configName)) {
            return mConfig.get(configName);
        }
        return false;
    }

    @Override
    public void setConfig(String configName, boolean newValue) {
        if (mConfig == null) {
            mConfig = new HashMap<>();
        }
        mConfig.put(configName, newValue);
    }
}
+0 −66
Original line number Diff line number Diff line
/*
 * Copyright (C) 2017 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.android.internal.logging.legacy;

import android.util.Log;

import android.metrics.LogMaker;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;

/**
 * Parse the Android lockscreen gesture logs.
 * @hide
 */
public class PowerScreenStateParser extends TagParser {
    private static final String TAG = "PowerScreenStateParser";
    private static final int EVENTLOG_TAG = 2728;

    // source of truth is android.view.WindowManagerPolicy, why:
    // 0: on
    // 1: OFF_BECAUSE_OF_ADMIN
    // 2: OFF_BECAUSE_OF_USER
    // 3: OFF_BECAUSE_OF_TIMEOUT

    @Override
    public int getTag() {
        return EVENTLOG_TAG;
    }

    @Override
    public void parseEvent(TronLogger logger, long eventTimeMs, Object[] operands) {
        final boolean debug = Util.debug();
        if (operands.length >= 2) {
            try {
                // (offOrOn|1|5),(becauseOfUser|1|5),(totalTouchDownTime|2|3),(touchCycles|1|1)
                boolean state = (((Integer) operands[0]).intValue()) == 1;
                int why = ((Integer) operands[1]).intValue();

                LogMaker proto = logger.obtain();
                proto.setCategory(MetricsEvent.SCREEN);
                proto.setType(state ? MetricsEvent.TYPE_OPEN : MetricsEvent.TYPE_CLOSE);
                proto.setTimestamp(eventTimeMs);
                proto.setSubtype(why);
                logger.addEvent(proto);
            } catch (ClassCastException e) {
                if (debug) {
                    Log.e(TAG, "unexpected operand type: ", e);
                }
            }
        } else if (debug) {
            Log.w(TAG, "wrong number of operands: " + operands.length);
        }
    }
}
Loading