blob: 598f0d51c1b9598167900748fb8ba239cb2ac2b2 [file] [log] [blame]
/*
* 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);
}
}
}
}