From 58ab9d81c3c1630970f1fafee14f1bee1843c5a7 Mon Sep 17 00:00:00 2001 From: Atneya Nair Date: Thu, 13 Apr 2023 16:18:18 -0700 Subject: [PATCH] Add SoundTrigger event types for logging - Encapsulate event types for use with EventLogger - Separate events into service-wide and sessioned events - Enumerate event types for all methods - Optional error string for distinguishing error events Bug: 272147641 Fixes: 278138038 Test: atest SoundTriggerEventTest Change-Id: I74075402f4c82aeb79444fd4d5ed17c38d97542e --- .../soundtrigger/SoundTriggerEventTest.java | 87 +++++++++++ .../soundtrigger/SoundTriggerEvent.java | 135 ++++++++++++++++++ 2 files changed, 222 insertions(+) create mode 100644 services/tests/voiceinteractiontests/src/com/android/server/soundtrigger/SoundTriggerEventTest.java create mode 100644 services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerEvent.java diff --git a/services/tests/voiceinteractiontests/src/com/android/server/soundtrigger/SoundTriggerEventTest.java b/services/tests/voiceinteractiontests/src/com/android/server/soundtrigger/SoundTriggerEventTest.java new file mode 100644 index 0000000000000..1c8950696f59d --- /dev/null +++ b/services/tests/voiceinteractiontests/src/com/android/server/soundtrigger/SoundTriggerEventTest.java @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2023 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.server.soundtrigger; + +import static com.google.common.truth.Truth.assertThat; + +import androidx.test.runner.AndroidJUnit4; + +import com.android.server.soundtrigger.SoundTriggerEvent.ServiceEvent; +import com.android.server.soundtrigger.SoundTriggerEvent.SessionEvent; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.util.UUID; + +@RunWith(AndroidJUnit4.class) +public final class SoundTriggerEventTest { + private static final ServiceEvent.Type serviceEventType = ServiceEvent.Type.ATTACH; + private static final SessionEvent.Type sessionEventType = SessionEvent.Type.DETACH; + + @Test + public void serviceEventNoPackageNoError_getStringContainsType() { + final var event = new ServiceEvent(serviceEventType); + final var stringRep = event.eventToString(); + assertThat(stringRep).contains(serviceEventType.name()); + assertThat(stringRep).ignoringCase().doesNotContain("error"); + } + + @Test + public void serviceEventPackageNoError_getStringContainsTypeAndPackage() { + final var packageName = "com.android.package.name"; + final var event = new ServiceEvent(serviceEventType, packageName); + final var stringRep = event.eventToString(); + assertThat(stringRep).contains(serviceEventType.name()); + assertThat(stringRep).contains(packageName); + assertThat(stringRep).ignoringCase().doesNotContain("error"); + } + + @Test + public void serviceEventPackageError_getStringContainsTypeAndPackageAndErrorAndMessage() { + final var packageName = "com.android.package.name"; + final var errorString = "oh no an ERROR occurred"; + final var event = new ServiceEvent(serviceEventType, packageName, errorString); + final var stringRep = event.eventToString(); + assertThat(stringRep).contains(serviceEventType.name()); + assertThat(stringRep).contains(packageName); + assertThat(stringRep).contains(errorString); + assertThat(stringRep).ignoringCase().contains("error"); + } + + @Test + public void sessionEventUUIDNoError_getStringContainsUUID() { + final var uuid = new UUID(5, -7); + final var event = new SessionEvent(sessionEventType, uuid); + final var stringRep = event.eventToString(); + assertThat(stringRep).contains(sessionEventType.name()); + assertThat(stringRep).contains(uuid.toString()); + assertThat(stringRep).ignoringCase().doesNotContain("error"); + } + + @Test + public void sessionEventUUIDError_getStringContainsUUIDAndError() { + final var uuid = new UUID(5, -7); + final var errorString = "oh no an ERROR occurred"; + final var event = new SessionEvent(sessionEventType, uuid, errorString); + final var stringRep = event.eventToString(); + assertThat(stringRep).contains(sessionEventType.name()); + assertThat(stringRep).contains(uuid.toString()); + assertThat(stringRep).ignoringCase().contains("error"); + assertThat(stringRep).contains(errorString); + } +} diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerEvent.java b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerEvent.java new file mode 100644 index 0000000000000..2a55496d2cd1c --- /dev/null +++ b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerEvent.java @@ -0,0 +1,135 @@ +/** + * Copyright (C) 2023 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.server.soundtrigger; + +import android.util.Slog; + +import com.android.server.utils.EventLogger.Event; + +import java.util.UUID; + +public abstract class SoundTriggerEvent extends Event { + + @Override + public Event printLog(int type, String tag) { + switch (type) { + case ALOGI: + Slog.i(tag, eventToString()); + break; + case ALOGE: + Slog.e(tag, eventToString()); + break; + case ALOGW: + Slog.w(tag, eventToString()); + break; + case ALOGV: + default: + Slog.v(tag, eventToString()); + } + return this; + } + + public static class ServiceEvent extends SoundTriggerEvent { + public enum Type { + ATTACH, + LIST_MODULE, + DETACH, + } + + private final Type mType; + private final String mPackageName; + private final String mErrorString; + + public ServiceEvent(Type type) { + this(type, null, null); + } + + public ServiceEvent(Type type, String packageName) { + this(type, packageName, null); + } + + public ServiceEvent(Type type, String packageName, String errorString) { + mType = type; + mPackageName = packageName; + mErrorString = errorString; + } + + @Override + public String eventToString() { + var res = new StringBuilder(String.format("%-12s", mType.name())); + if (mErrorString != null) { + res.append(" ERROR: ").append(mErrorString); + } + if (mPackageName != null) { + res.append(" for: ").append(mPackageName); + } + return res.toString(); + } + } + + public static class SessionEvent extends SoundTriggerEvent { + public enum Type { + // Downward calls + START_RECOGNITION, + STOP_RECOGNITION, + LOAD_MODEL, + UNLOAD_MODEL, + UPDATE_MODEL, + DELETE_MODEL, + START_RECOGNITION_SERVICE, + STOP_RECOGNITION_SERVICE, + GET_MODEL_STATE, + SET_PARAMETER, + GET_MODULE_PROPERTIES, + DETACH, + // Callback events + RECOGNITION, + RESUME, + RESUME_FAILED, + PAUSE, + PAUSE_FAILED, + RESOURCES_AVAILABLE, + MODULE_DIED + } + + private final UUID mModelUuid; + private final Type mType; + private final String mErrorString; + + public SessionEvent(Type type, UUID modelUuid, String errorString) { + mType = type; + mModelUuid = modelUuid; + mErrorString = errorString; + } + + public SessionEvent(Type type, UUID modelUuid) { + this(type, modelUuid, null); + } + + @Override + public String eventToString() { + var res = new StringBuilder(String.format("%-25s", mType.name())); + if (mErrorString != null) { + res.append(" ERROR: ").append(mErrorString); + } + if (mModelUuid != null) { + res.append(" for: ").append(mModelUuid); + } + return res.toString(); + } + } +}