diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto index b0570fd83bbf8..d78de75a60bdc 100644 --- a/cmds/statsd/src/atoms.proto +++ b/cmds/statsd/src/atoms.proto @@ -164,7 +164,7 @@ message Atom { BiometricAcquired biometric_acquired = 87; BiometricAuthenticated biometric_authenticated = 88; BiometricErrorOccurred biometric_error_occurred = 89; - // Atom number 90 is available for use. + UiEventReported ui_event_reported = 90; BatteryHealthSnapshot battery_health_snapshot = 91; SlowIo slow_io = 92; BatteryCausedShutdown battery_caused_shutdown = 93; @@ -3265,6 +3265,21 @@ message GenericAtom { optional android.stats.EventType event_id = 2; } +/** + * Atom for simple logging of user interaction and impression events, such as "the user touched + * this button" or "this dialog was displayed". + * Keep the UI event stream clean: don't use for system or background events. + * Log using the UiEventLogger wrapper - don't write with the StatsLog API directly. + */ +message UiEventReported { + // The event_id. + optional int32 event_id = 1; + // The event's source or target uid and package, if applicable. + // For example, the package posting a notification, or the destination package of a share. + optional int32 uid = 2 [(is_uid) = true]; + optional string package_name = 3; +} + /** * Logs when a biometric acquire event occurs. * diff --git a/core/java/com/android/internal/logging/UiEvent.java b/core/java/com/android/internal/logging/UiEvent.java new file mode 100644 index 0000000000000..0407b0704e80b --- /dev/null +++ b/core/java/com/android/internal/logging/UiEvent.java @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2019 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; + +import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.RetentionPolicy.SOURCE; + +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +@Retention(SOURCE) +@Target(FIELD) +public @interface UiEvent { + /** An explanation, suitable for Android analysts, of the UI event that this log represents. */ + String doc(); +} diff --git a/core/java/com/android/internal/logging/UiEventLogger.java b/core/java/com/android/internal/logging/UiEventLogger.java new file mode 100644 index 0000000000000..cca97f689f4ee --- /dev/null +++ b/core/java/com/android/internal/logging/UiEventLogger.java @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2019 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; + +/** + * Logging interface for UI events. Normal implementation is UiEventLoggerImpl. + * For testing, use fake implementation UiEventLoggerFake. + * + * See go/sysui-event-logs and UiEventReported atom in atoms.proto. + */ +public interface UiEventLogger { + /** Put your Event IDs in enums that implement this interface, and document them using the + * UiEventEnum annotation. + * Event IDs must be globally unique. This will be enforced by tooling (forthcoming). + * OEMs should use event IDs above 100000. + */ + interface UiEventEnum { + int getId(); + } + /** + * Log a simple event, with no package or instance ID. + */ + void log(UiEventEnum eventID); +} diff --git a/core/java/com/android/internal/logging/UiEventLoggerImpl.java b/core/java/com/android/internal/logging/UiEventLoggerImpl.java new file mode 100644 index 0000000000000..e64fba2d2a310 --- /dev/null +++ b/core/java/com/android/internal/logging/UiEventLoggerImpl.java @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2019 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; + +import android.util.StatsLog; + +/** + * Standard implementation of UiEventLogger, writing to StatsLog. + * + * See UiEventReported atom in atoms.proto for more context. + */ +public class UiEventLoggerImpl implements UiEventLogger { + /** + * Log a simple event, with no package or instance ID. + */ + @Override + public void log(UiEventEnum event) { + final int eventID = event.getId(); + if (eventID > 0) { + StatsLog.write(StatsLog.UI_EVENT_REPORTED, eventID, 0, null); + } + } +} diff --git a/core/java/com/android/internal/logging/testing/UiEventLoggerFake.java b/core/java/com/android/internal/logging/testing/UiEventLoggerFake.java new file mode 100644 index 0000000000000..92e9bbb77bd3e --- /dev/null +++ b/core/java/com/android/internal/logging/testing/UiEventLoggerFake.java @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2019 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.testing; + +import com.android.internal.logging.UiEventLogger; + +import java.util.LinkedList; +import java.util.Queue; + +/** + * Fake logger that queues up logged events for inspection. + * + * @hide. + */ +public class UiEventLoggerFake implements UiEventLogger { + /** + * Immutable data class used to record fake log events. + */ + public class FakeUiEvent { + public final int eventId; + public final int uid; + public final String packageName; + + public FakeUiEvent(int eventId, int uid, String packageName) { + this.eventId = eventId; + this.uid = uid; + this.packageName = packageName; + } + } + + private Queue mLogs = new LinkedList(); + + @Override + public void log(UiEventEnum event) { + final int eventId = event.getId(); + if (eventId > 0) { + mLogs.offer(new FakeUiEvent(eventId, 0, null)); + } + } + + public Queue getLogs() { + return mLogs; + } +}