Merge changes I69bc716c,Ifc184548,I74075402 into udc-dev
* changes: Sessionize STMiddleware logging SoundTriggerService logging cleanup Add SoundTrigger event types for logging
This commit is contained in:
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
package com.android.server.soundtrigger_middleware;
|
||||
|
||||
import static com.android.server.soundtrigger_middleware.SoundTriggerMiddlewareLogging.ServiceEvent;
|
||||
import static com.android.server.soundtrigger_middleware.SoundTriggerMiddlewareLogging.SessionEvent;
|
||||
import static com.android.internal.util.LatencyTracker.ACTION_SHOW_VOICE_INTERACTION;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
@@ -55,6 +57,9 @@ import java.util.Optional;
|
||||
|
||||
@RunWith(JUnit4.class)
|
||||
public class SoundTriggerMiddlewareLoggingTest {
|
||||
private static final ServiceEvent.Type SERVICE_TYPE = ServiceEvent.Type.ATTACH;
|
||||
private static final SessionEvent.Type SESSION_TYPE = SessionEvent.Type.LOAD_MODEL;
|
||||
|
||||
private FakeLatencyTracker mLatencyTracker;
|
||||
@Mock
|
||||
private BatteryStatsInternal mBatteryStatsInternal;
|
||||
@@ -184,4 +189,138 @@ public class SoundTriggerMiddlewareLoggingTest {
|
||||
callback.onPhraseRecognition(0 /* modelHandle */, successEventWithKeyphraseId,
|
||||
0 /* captureSession */);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void serviceEventException_getStringContainsInfo() {
|
||||
String packageName = "com.android.test";
|
||||
Exception exception = new Exception("test");
|
||||
Object param1 = new Object();
|
||||
Object param2 = new Object();
|
||||
final var event = ServiceEvent.createForException(
|
||||
SERVICE_TYPE, packageName, exception, param1, param2);
|
||||
final var stringRep = event.eventToString();
|
||||
assertThat(stringRep).contains(SERVICE_TYPE.name());
|
||||
assertThat(stringRep).contains(packageName);
|
||||
assertThat(stringRep).contains(exception.toString());
|
||||
assertThat(stringRep).contains(param1.toString());
|
||||
assertThat(stringRep).contains(param2.toString());
|
||||
assertThat(stringRep).ignoringCase().contains("error");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void serviceEventExceptionNoArgs_getStringContainsInfo() {
|
||||
String packageName = "com.android.test";
|
||||
Exception exception = new Exception("test");
|
||||
final var event = ServiceEvent.createForException(
|
||||
SERVICE_TYPE, packageName, exception);
|
||||
final var stringRep = event.eventToString();
|
||||
assertThat(stringRep).contains(SERVICE_TYPE.name());
|
||||
assertThat(stringRep).contains(packageName);
|
||||
assertThat(stringRep).contains(exception.toString());
|
||||
assertThat(stringRep).ignoringCase().contains("error");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void serviceEventReturn_getStringContainsInfo() {
|
||||
String packageName = "com.android.test";
|
||||
Object param1 = new Object();
|
||||
Object param2 = new Object();
|
||||
Object retValue = new Object();
|
||||
final var event = ServiceEvent.createForReturn(
|
||||
SERVICE_TYPE, packageName, retValue, param1, param2);
|
||||
final var stringRep = event.eventToString();
|
||||
assertThat(stringRep).contains(SERVICE_TYPE.name());
|
||||
assertThat(stringRep).contains(packageName);
|
||||
assertThat(stringRep).contains(retValue.toString());
|
||||
assertThat(stringRep).contains(param1.toString());
|
||||
assertThat(stringRep).contains(param2.toString());
|
||||
assertThat(stringRep).ignoringCase().doesNotContain("error");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void serviceEventReturnNoArgs_getStringContainsInfo() {
|
||||
String packageName = "com.android.test";
|
||||
Object retValue = new Object();
|
||||
final var event = ServiceEvent.createForReturn(
|
||||
SERVICE_TYPE, packageName, retValue);
|
||||
final var stringRep = event.eventToString();
|
||||
assertThat(stringRep).contains(SERVICE_TYPE.name());
|
||||
assertThat(stringRep).contains(packageName);
|
||||
assertThat(stringRep).contains(retValue.toString());
|
||||
assertThat(stringRep).ignoringCase().doesNotContain("error");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void sessionEventException_getStringContainsInfo() {
|
||||
Object param1 = new Object();
|
||||
Object param2 = new Object();
|
||||
Exception exception = new Exception("test");
|
||||
final var event = SessionEvent.createForException(
|
||||
SESSION_TYPE, exception, param1, param2);
|
||||
final var stringRep = event.eventToString();
|
||||
assertThat(stringRep).contains(SESSION_TYPE.name());
|
||||
assertThat(stringRep).contains(exception.toString());
|
||||
assertThat(stringRep).contains(param1.toString());
|
||||
assertThat(stringRep).contains(param2.toString());
|
||||
assertThat(stringRep).ignoringCase().contains("error");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void sessionEventExceptionNoArgs_getStringContainsInfo() {
|
||||
Exception exception = new Exception("test");
|
||||
final var event = SessionEvent.createForException(
|
||||
SESSION_TYPE, exception);
|
||||
final var stringRep = event.eventToString();
|
||||
assertThat(stringRep).contains(SESSION_TYPE.name());
|
||||
assertThat(stringRep).contains(exception.toString());
|
||||
assertThat(stringRep).ignoringCase().contains("error");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void sessionEventReturn_getStringContainsInfo() {
|
||||
Object param1 = new Object();
|
||||
Object param2 = new Object();
|
||||
Object retValue = new Object();
|
||||
final var event = SessionEvent.createForReturn(
|
||||
SESSION_TYPE, retValue, param1, param2);
|
||||
final var stringRep = event.eventToString();
|
||||
assertThat(stringRep).contains(SESSION_TYPE.name());
|
||||
assertThat(stringRep).contains(retValue.toString());
|
||||
assertThat(stringRep).contains(param1.toString());
|
||||
assertThat(stringRep).contains(param2.toString());
|
||||
assertThat(stringRep).ignoringCase().doesNotContain("error");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void sessionEventReturnNoArgs_getStringContainsInfo() {
|
||||
Object retValue = new Object();
|
||||
final var event = SessionEvent.createForReturn(
|
||||
SESSION_TYPE, retValue);
|
||||
final var stringRep = event.eventToString();
|
||||
assertThat(stringRep).contains(SESSION_TYPE.name());
|
||||
assertThat(stringRep).contains(retValue.toString());
|
||||
assertThat(stringRep).ignoringCase().doesNotContain("error");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void sessionEventVoid_getStringContainsInfo() {
|
||||
Object param1 = new Object();
|
||||
Object param2 = new Object();
|
||||
final var event = SessionEvent.createForVoid(
|
||||
SESSION_TYPE, param1, param2);
|
||||
final var stringRep = event.eventToString();
|
||||
assertThat(stringRep).contains(SESSION_TYPE.name());
|
||||
assertThat(stringRep).contains(param1.toString());
|
||||
assertThat(stringRep).contains(param2.toString());
|
||||
assertThat(stringRep).ignoringCase().doesNotContain("error");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void sessionEventVoidNoArgs_getStringContainsInfo() {
|
||||
final var event = SessionEvent.createForVoid(
|
||||
SESSION_TYPE);
|
||||
final var stringRep = event.eventToString();
|
||||
assertThat(stringRep).contains(SESSION_TYPE.name());
|
||||
assertThat(stringRep).ignoringCase().doesNotContain("error");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,9 @@
|
||||
|
||||
package com.android.server.soundtrigger;
|
||||
|
||||
import static com.android.server.soundtrigger.SoundTriggerEvent.SessionEvent.Type;
|
||||
import static com.android.server.utils.EventLogger.Event.ALOGW;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.content.BroadcastReceiver;
|
||||
@@ -51,6 +54,9 @@ import android.util.Slog;
|
||||
|
||||
import com.android.internal.annotations.GuardedBy;
|
||||
import com.android.internal.logging.MetricsLogger;
|
||||
import com.android.server.soundtrigger.SoundTriggerEvent.SessionEvent;
|
||||
import com.android.server.utils.EventLogger.Event;
|
||||
import com.android.server.utils.EventLogger;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.PrintWriter;
|
||||
@@ -76,7 +82,6 @@ import java.util.function.Supplier;
|
||||
*/
|
||||
public class SoundTriggerHelper implements SoundTrigger.StatusListener {
|
||||
static final String TAG = "SoundTriggerHelper";
|
||||
static final boolean DBG = false;
|
||||
|
||||
// Module ID if there is no available module to connect to.
|
||||
public static final int INVALID_MODULE_ID = -1;
|
||||
@@ -129,11 +134,12 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
|
||||
private final int mModuleId;
|
||||
private final Function<SoundTrigger.StatusListener, SoundTriggerModule> mModuleProvider;
|
||||
private final Supplier<List<ModuleProperties>> mModulePropertiesProvider;
|
||||
private final EventLogger mEventLogger;
|
||||
|
||||
@GuardedBy("mLock")
|
||||
private boolean mIsDetached = false;
|
||||
|
||||
SoundTriggerHelper(Context context,
|
||||
SoundTriggerHelper(Context context, EventLogger eventLogger,
|
||||
@NonNull Function<SoundTrigger.StatusListener, SoundTriggerModule> moduleProvider,
|
||||
int moduleId,
|
||||
@NonNull Supplier<List<ModuleProperties>> modulePropertiesProvider) {
|
||||
@@ -144,6 +150,7 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
|
||||
mModelDataMap = new HashMap<UUID, ModelData>();
|
||||
mKeyphraseUuidMap = new HashMap<Integer, UUID>();
|
||||
mModuleProvider = moduleProvider;
|
||||
mEventLogger = eventLogger;
|
||||
mModulePropertiesProvider = modulePropertiesProvider;
|
||||
if (moduleId == INVALID_MODULE_ID) {
|
||||
mModule = null;
|
||||
@@ -234,14 +241,6 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
|
||||
throw new IllegalStateException("SoundTriggerHelper has been detached");
|
||||
}
|
||||
|
||||
if (DBG) {
|
||||
Slog.d(TAG, "startKeyphraseRecognition for keyphraseId=" + keyphraseId
|
||||
+ " soundModel=" + soundModel + ", callback=" + callback.asBinder()
|
||||
+ ", recognitionConfig=" + recognitionConfig
|
||||
+ ", runInBatterySaverMode=" + runInBatterySaverMode);
|
||||
dumpModelStateLocked();
|
||||
}
|
||||
|
||||
ModelData model = getKeyphraseModelDataLocked(keyphraseId);
|
||||
if (model != null && !model.isKeyphraseModel()) {
|
||||
Slog.e(TAG, "Generic model with same UUID exists.");
|
||||
@@ -301,9 +300,6 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
|
||||
}
|
||||
modelData.setHandle(handle[0]);
|
||||
modelData.setLoaded();
|
||||
if (DBG) {
|
||||
Slog.d(TAG, "prepareForRecognition: Sound model loaded with handle:" + handle[0]);
|
||||
}
|
||||
}
|
||||
return STATUS_OK;
|
||||
}
|
||||
@@ -448,13 +444,6 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
|
||||
if (DBG) {
|
||||
Slog.d(TAG, "stopRecognition for keyphraseId=" + keyphraseId + ", callback =" +
|
||||
callback.asBinder());
|
||||
Slog.d(TAG, "current callback="
|
||||
+ ((modelData == null || modelData.getCallback() == null) ? "null" :
|
||||
modelData.getCallback().asBinder()));
|
||||
}
|
||||
int status = stopRecognition(modelData, callback);
|
||||
if (status != SoundTrigger.STATUS_OK) {
|
||||
return status;
|
||||
@@ -635,7 +624,6 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
|
||||
|
||||
// Remove it from existence.
|
||||
mModelDataMap.remove(modelId);
|
||||
if (DBG) dumpModelStateLocked();
|
||||
return status;
|
||||
}
|
||||
}
|
||||
@@ -797,7 +785,6 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
|
||||
return;
|
||||
}
|
||||
|
||||
if (DBG) Slog.d(TAG, "onRecognition: " + event);
|
||||
synchronized (mLock) {
|
||||
switch (event.status) {
|
||||
case SoundTrigger.RECOGNITION_STATUS_ABORT:
|
||||
@@ -845,12 +832,14 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
|
||||
}
|
||||
|
||||
try {
|
||||
mEventLogger.enqueue(new SessionEvent(Type.RECOGNITION, model.getModelId()));
|
||||
callback.onGenericSoundTriggerDetected((GenericRecognitionEvent) event);
|
||||
} catch (DeadObjectException e) {
|
||||
} catch (RemoteException e) {
|
||||
mEventLogger.enqueue(new SessionEvent(
|
||||
Type.RECOGNITION, model.getModelId(), "RemoteException")
|
||||
.printLog(ALOGW, TAG));
|
||||
forceStopAndUnloadModelLocked(model, e);
|
||||
return;
|
||||
} catch (RemoteException e) {
|
||||
Slog.w(TAG, "RemoteException in onGenericSoundTriggerDetected", e);
|
||||
}
|
||||
|
||||
RecognitionConfig config = model.getRecognitionConfig();
|
||||
@@ -869,7 +858,6 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
|
||||
|
||||
@Override
|
||||
public void onModelUnloaded(int modelHandle) {
|
||||
if (DBG) Slog.d(TAG, "onModelUnloaded: " + modelHandle);
|
||||
synchronized (mLock) {
|
||||
MetricsLogger.count(mContext, "sth_sound_model_updated", 1);
|
||||
onModelUnloadedLocked(modelHandle);
|
||||
@@ -878,7 +866,6 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
|
||||
|
||||
@Override
|
||||
public void onResourcesAvailable() {
|
||||
if (DBG) Slog.d(TAG, "onResourcesAvailable");
|
||||
synchronized (mLock) {
|
||||
onResourcesAvailableLocked();
|
||||
}
|
||||
@@ -920,6 +907,7 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
|
||||
}
|
||||
|
||||
private void onResourcesAvailableLocked() {
|
||||
mEventLogger.enqueue(new SessionEvent(Type.RESOURCES_AVAILABLE, null));
|
||||
updateAllRecognitionsLocked();
|
||||
}
|
||||
|
||||
@@ -932,12 +920,14 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
|
||||
try {
|
||||
IRecognitionStatusCallback callback = modelData.getCallback();
|
||||
if (callback != null) {
|
||||
mEventLogger.enqueue(new SessionEvent(Type.PAUSE, modelData.getModelId()));
|
||||
callback.onRecognitionPaused();
|
||||
}
|
||||
} catch (DeadObjectException e) {
|
||||
forceStopAndUnloadModelLocked(modelData, e);
|
||||
} catch (RemoteException e) {
|
||||
Slog.w(TAG, "RemoteException in onRecognitionPaused", e);
|
||||
mEventLogger.enqueue(new SessionEvent(
|
||||
Type.PAUSE, modelData.getModelId(), "RemoteException")
|
||||
.printLog(ALOGW, TAG));
|
||||
forceStopAndUnloadModelLocked(modelData, e);
|
||||
}
|
||||
updateRecognitionLocked(modelData, true);
|
||||
}
|
||||
@@ -979,12 +969,14 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
|
||||
}
|
||||
|
||||
try {
|
||||
mEventLogger.enqueue(new SessionEvent(Type.RECOGNITION, modelData.getModelId()));
|
||||
modelData.getCallback().onKeyphraseDetected((KeyphraseRecognitionEvent) event);
|
||||
} catch (DeadObjectException e) {
|
||||
} catch (RemoteException e) {
|
||||
mEventLogger.enqueue(new SessionEvent(
|
||||
Type.RECOGNITION, modelData.getModelId(), "RemoteException")
|
||||
.printLog(ALOGW, TAG));
|
||||
forceStopAndUnloadModelLocked(modelData, e);
|
||||
return;
|
||||
} catch (RemoteException e) {
|
||||
Slog.w(TAG, "RemoteException in onKeyphraseDetected", e);
|
||||
}
|
||||
|
||||
RecognitionConfig config = modelData.getRecognitionConfig();
|
||||
@@ -1036,10 +1028,13 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
|
||||
IRecognitionStatusCallback callback = modelData.getCallback();
|
||||
if (callback != null) {
|
||||
try {
|
||||
mEventLogger.enqueue(new SessionEvent(Type.MODULE_DIED,
|
||||
modelData.getModelId()).printLog(ALOGW, TAG));
|
||||
callback.onModuleDied();
|
||||
} catch (RemoteException e) {
|
||||
Slog.w(TAG, "RemoteException send moduleDied for model handle " +
|
||||
modelData.getHandle(), e);
|
||||
mEventLogger.enqueue(new SessionEvent(Type.MODULE_DIED,
|
||||
modelData.getModelId(), "RemoteException")
|
||||
.printLog(ALOGW, TAG));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1085,7 +1080,6 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
|
||||
|
||||
@Override
|
||||
public void onCallStateChanged(int state, String arg1) {
|
||||
if (DBG) Slog.d(TAG, "onCallStateChanged: " + state);
|
||||
|
||||
if (mHandler != null) {
|
||||
synchronized (mLock) {
|
||||
@@ -1107,9 +1101,6 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
|
||||
}
|
||||
@SoundTriggerPowerSaveMode int soundTriggerPowerSaveMode =
|
||||
mPowerManager.getSoundTriggerPowerSaveMode();
|
||||
if (DBG) {
|
||||
Slog.d(TAG, "onPowerSaveModeChanged: " + soundTriggerPowerSaveMode);
|
||||
}
|
||||
synchronized (mLock) {
|
||||
onPowerSaveModeChangedLocked(soundTriggerPowerSaveMode);
|
||||
}
|
||||
@@ -1151,13 +1142,13 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
|
||||
public void detach() {
|
||||
synchronized (mLock) {
|
||||
if (mIsDetached) return;
|
||||
mIsDetached = true;
|
||||
for (ModelData model : mModelDataMap.values()) {
|
||||
forceStopAndUnloadModelLocked(model, null);
|
||||
}
|
||||
mModelDataMap.clear();
|
||||
internalClearGlobalStateLocked();
|
||||
if (mModule != null) {
|
||||
mIsDetached = true;
|
||||
mModule.detach();
|
||||
mModule = null;
|
||||
}
|
||||
@@ -1361,11 +1352,16 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
|
||||
// Notify of error if needed.
|
||||
if (notifyClientOnError) {
|
||||
try {
|
||||
mEventLogger.enqueue(new SessionEvent(Type.RESUME_FAILED,
|
||||
modelData.getModelId(), String.valueOf(status))
|
||||
.printLog(ALOGW, TAG));
|
||||
callback.onResumeFailed(status);
|
||||
} catch (DeadObjectException e) {
|
||||
forceStopAndUnloadModelLocked(modelData, e);
|
||||
} catch (RemoteException e) {
|
||||
Slog.w(TAG, "RemoteException in onResumeFailed", e);
|
||||
mEventLogger.enqueue(new SessionEvent(Type.RESUME_FAILED,
|
||||
modelData.getModelId(),
|
||||
String.valueOf(status) + " - RemoteException")
|
||||
.printLog(ALOGW, TAG));
|
||||
forceStopAndUnloadModelLocked(modelData, e);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -1375,17 +1371,16 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
|
||||
// Notify of resume if needed.
|
||||
if (notifyClientOnError) {
|
||||
try {
|
||||
mEventLogger.enqueue(new SessionEvent(Type.RESUME,
|
||||
modelData.getModelId()));
|
||||
callback.onRecognitionResumed();
|
||||
} catch (DeadObjectException e) {
|
||||
forceStopAndUnloadModelLocked(modelData, e);
|
||||
} catch (RemoteException e) {
|
||||
Slog.w(TAG, "RemoteException in onRecognitionResumed", e);
|
||||
mEventLogger.enqueue(new SessionEvent(Type.RESUME,
|
||||
modelData.getModelId(), "RemoteException").printLog(ALOGW, TAG));
|
||||
forceStopAndUnloadModelLocked(modelData, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (DBG) {
|
||||
Slog.d(TAG, "Model being started :" + modelData.toString());
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
@@ -1405,11 +1400,16 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
|
||||
MetricsLogger.count(mContext, "sth_stop_recognition_error", 1);
|
||||
if (notify) {
|
||||
try {
|
||||
mEventLogger.enqueue(new SessionEvent(Type.PAUSE_FAILED,
|
||||
modelData.getModelId(), String.valueOf(status))
|
||||
.printLog(ALOGW, TAG));
|
||||
callback.onPauseFailed(status);
|
||||
} catch (DeadObjectException e) {
|
||||
forceStopAndUnloadModelLocked(modelData, e);
|
||||
} catch (RemoteException e) {
|
||||
Slog.w(TAG, "RemoteException in onPauseFailed", e);
|
||||
mEventLogger.enqueue(new SessionEvent(Type.PAUSE_FAILED,
|
||||
modelData.getModelId(),
|
||||
String.valueOf(status) + " - RemoteException")
|
||||
.printLog(ALOGW, TAG));
|
||||
forceStopAndUnloadModelLocked(modelData, e);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -1418,27 +1418,19 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
|
||||
// Notify of pause if needed.
|
||||
if (notify) {
|
||||
try {
|
||||
mEventLogger.enqueue(new SessionEvent(Type.PAUSE,
|
||||
modelData.getModelId()));
|
||||
callback.onRecognitionPaused();
|
||||
} catch (DeadObjectException e) {
|
||||
forceStopAndUnloadModelLocked(modelData, e);
|
||||
} catch (RemoteException e) {
|
||||
Slog.w(TAG, "RemoteException in onRecognitionPaused", e);
|
||||
mEventLogger.enqueue(new SessionEvent(Type.PAUSE,
|
||||
modelData.getModelId(), "RemoteException").printLog(ALOGW, TAG));
|
||||
forceStopAndUnloadModelLocked(modelData, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (DBG) {
|
||||
Slog.d(TAG, "Model being stopped :" + modelData.toString());
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
private void dumpModelStateLocked() {
|
||||
for (UUID modelId : mModelDataMap.keySet()) {
|
||||
ModelData modelData = mModelDataMap.get(modelId);
|
||||
Slog.i(TAG, "Model :" + modelData.toString());
|
||||
}
|
||||
}
|
||||
|
||||
// Computes whether we have any recognition running at all (voice or generic). Sets
|
||||
// the mRecognitionRequested variable with the result.
|
||||
private boolean computeRecognitionRequestedLocked() {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -44,6 +44,16 @@ class ObjectPrinter {
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as {@link #print(StringBuilder, Object, int)} with default max length.
|
||||
*
|
||||
* @param builder StringBuilder to print into.
|
||||
* @param obj The object to print.
|
||||
*/
|
||||
static void print(@NonNull StringBuilder builder, @Nullable Object obj) {
|
||||
print(builder, obj, kDefaultMaxCollectionLength);
|
||||
}
|
||||
|
||||
/**
|
||||
* A version of {@link #print(Object, int)} that uses a {@link StringBuilder}.
|
||||
*
|
||||
|
||||
@@ -16,6 +16,10 @@
|
||||
|
||||
package com.android.server.soundtrigger_middleware;
|
||||
|
||||
import static com.android.server.soundtrigger_middleware.SoundTriggerMiddlewareLogging.SessionEvent.Type.*;
|
||||
import static com.android.server.utils.EventLogger.Event.ALOGI;
|
||||
import static com.android.server.utils.EventLogger.Event.ALOGW;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.content.Context;
|
||||
@@ -41,13 +45,20 @@ import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.internal.util.ArrayUtils;
|
||||
import com.android.internal.util.LatencyTracker;
|
||||
import com.android.server.LocalServices;
|
||||
import com.android.server.utils.EventLogger.Event;
|
||||
import com.android.server.utils.EventLogger;
|
||||
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.LinkedBlockingDeque;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.Deque;
|
||||
|
||||
|
||||
/**
|
||||
* An ISoundTriggerMiddlewareService decorator, which adds logging of all API calls (and
|
||||
@@ -74,9 +85,17 @@ import java.util.function.Supplier;
|
||||
*/
|
||||
public class SoundTriggerMiddlewareLogging implements ISoundTriggerMiddlewareInternal, Dumpable {
|
||||
private static final String TAG = "SoundTriggerMiddlewareLogging";
|
||||
private static final int SESSION_MAX_EVENT_SIZE = 128;
|
||||
private final @NonNull ISoundTriggerMiddlewareInternal mDelegate;
|
||||
private final @NonNull LatencyTracker mLatencyTracker;
|
||||
private final @NonNull Supplier<BatteryStatsInternal> mBatteryStatsInternalSupplier;
|
||||
private final @NonNull EventLogger mServiceEventLogger = new EventLogger(256,
|
||||
"Service Events");
|
||||
|
||||
private final Set<EventLogger> mSessionEventLoggers = ConcurrentHashMap.newKeySet(4);
|
||||
private final Deque<EventLogger> mDetachedSessionEventLoggers = new LinkedBlockingDeque<>(4);
|
||||
private final AtomicInteger mSessionCount = new AtomicInteger(0);
|
||||
|
||||
|
||||
public SoundTriggerMiddlewareLogging(@NonNull Context context,
|
||||
@NonNull ISoundTriggerMiddlewareInternal delegate) {
|
||||
@@ -99,10 +118,19 @@ public class SoundTriggerMiddlewareLogging implements ISoundTriggerMiddlewareInt
|
||||
SoundTriggerModuleDescriptor[] listModules() {
|
||||
try {
|
||||
SoundTriggerModuleDescriptor[] result = mDelegate.listModules();
|
||||
logReturn("listModules", result);
|
||||
var moduleSummary = Arrays.stream(result).map((descriptor) ->
|
||||
new ModulePropertySummary(descriptor.handle,
|
||||
descriptor.properties.implementor,
|
||||
descriptor.properties.version)).toArray(ModulePropertySummary[]::new);
|
||||
|
||||
mServiceEventLogger.enqueue(ServiceEvent.createForReturn(
|
||||
ServiceEvent.Type.LIST_MODULE,
|
||||
IdentityContext.get().packageName, moduleSummary).printLog(ALOGI, TAG));
|
||||
return result;
|
||||
} catch (Exception e) {
|
||||
logException("listModules", e);
|
||||
mServiceEventLogger.enqueue(ServiceEvent.createForException(
|
||||
ServiceEvent.Type.LIST_MODULE,
|
||||
IdentityContext.get().packageName, e).printLog(ALOGW, TAG));
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
@@ -111,12 +139,29 @@ public class SoundTriggerMiddlewareLogging implements ISoundTriggerMiddlewareInt
|
||||
public @NonNull
|
||||
ISoundTriggerModule attach(int handle, ISoundTriggerCallback callback) {
|
||||
try {
|
||||
ModuleLogging result = new ModuleLogging(callback);
|
||||
result.attach(mDelegate.attach(handle, result.getCallbackWrapper()));
|
||||
logReturn("attach", result, handle, callback);
|
||||
var originatorIdentity = IdentityContext.getNonNull();
|
||||
String packageIdentification = originatorIdentity.packageName
|
||||
+ mSessionCount.getAndIncrement();
|
||||
ModuleLogging result = new ModuleLogging();
|
||||
var eventLogger = new EventLogger(SESSION_MAX_EVENT_SIZE,
|
||||
"Session logger for: " + packageIdentification);
|
||||
|
||||
var callbackWrapper = new CallbackLogging(callback, eventLogger, originatorIdentity);
|
||||
|
||||
result.attach(mDelegate.attach(handle, callbackWrapper), eventLogger);
|
||||
|
||||
mServiceEventLogger.enqueue(ServiceEvent.createForReturn(
|
||||
ServiceEvent.Type.ATTACH,
|
||||
packageIdentification, result, handle, callback)
|
||||
.printLog(ALOGI, TAG));
|
||||
|
||||
mSessionEventLoggers.add(eventLogger);
|
||||
return result;
|
||||
} catch (Exception e) {
|
||||
logException("attach", e, handle, callback);
|
||||
mServiceEventLogger.enqueue(ServiceEvent.createForException(
|
||||
ServiceEvent.Type.ATTACH,
|
||||
IdentityContext.get().packageName, e, handle, callback)
|
||||
.printLog(ALOGW, TAG));
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
@@ -127,44 +172,27 @@ public class SoundTriggerMiddlewareLogging implements ISoundTriggerMiddlewareInt
|
||||
return mDelegate.toString();
|
||||
}
|
||||
|
||||
private void logException(String methodName, Exception ex, Object... args) {
|
||||
logExceptionWithObject(this, IdentityContext.get(), methodName, ex, args);
|
||||
}
|
||||
|
||||
private void logReturn(String methodName, Object retVal, Object... args) {
|
||||
logReturnWithObject(this, IdentityContext.get(), methodName, retVal, args);
|
||||
}
|
||||
|
||||
private void logVoidReturn(String methodName, Object... args) {
|
||||
logVoidReturnWithObject(this, IdentityContext.get(), methodName, args);
|
||||
}
|
||||
|
||||
private class ModuleLogging implements ISoundTriggerModule {
|
||||
private ISoundTriggerModule mDelegate;
|
||||
private final @NonNull CallbackLogging mCallbackWrapper;
|
||||
private final @NonNull Identity mOriginatorIdentity;
|
||||
private EventLogger mEventLogger;
|
||||
|
||||
ModuleLogging(@NonNull ISoundTriggerCallback callback) {
|
||||
mCallbackWrapper = new CallbackLogging(callback);
|
||||
mOriginatorIdentity = IdentityContext.getNonNull();
|
||||
}
|
||||
|
||||
void attach(@NonNull ISoundTriggerModule delegate) {
|
||||
void attach(@NonNull ISoundTriggerModule delegate, EventLogger eventLogger) {
|
||||
mDelegate = delegate;
|
||||
}
|
||||
|
||||
ISoundTriggerCallback getCallbackWrapper() {
|
||||
return mCallbackWrapper;
|
||||
mEventLogger = eventLogger;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int loadModel(SoundModel model) throws RemoteException {
|
||||
try {
|
||||
int result = mDelegate.loadModel(model);
|
||||
logReturn("loadModel", result, model);
|
||||
mEventLogger.enqueue(SessionEvent.createForReturn(
|
||||
LOAD_MODEL, result, model.uuid)
|
||||
.printLog(ALOGI, TAG));
|
||||
return result;
|
||||
} catch (Exception e) {
|
||||
logException("loadModel", e, model);
|
||||
mEventLogger.enqueue(SessionEvent.createForReturn(
|
||||
LOAD_MODEL, e, model.uuid)
|
||||
.printLog(ALOGW, TAG));
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
@@ -173,10 +201,14 @@ public class SoundTriggerMiddlewareLogging implements ISoundTriggerMiddlewareInt
|
||||
public int loadPhraseModel(PhraseSoundModel model) throws RemoteException {
|
||||
try {
|
||||
int result = mDelegate.loadPhraseModel(model);
|
||||
logReturn("loadPhraseModel", result, model);
|
||||
mEventLogger.enqueue(SessionEvent.createForReturn(
|
||||
LOAD_PHRASE_MODEL, result, model.common.uuid)
|
||||
.printLog(ALOGI, TAG));
|
||||
return result;
|
||||
} catch (Exception e) {
|
||||
logException("loadPhraseModel", e, model);
|
||||
mEventLogger.enqueue(SessionEvent.createForException(
|
||||
LOAD_PHRASE_MODEL, e, model.common.uuid)
|
||||
.printLog(ALOGW, TAG));
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
@@ -185,9 +217,13 @@ public class SoundTriggerMiddlewareLogging implements ISoundTriggerMiddlewareInt
|
||||
public void unloadModel(int modelHandle) throws RemoteException {
|
||||
try {
|
||||
mDelegate.unloadModel(modelHandle);
|
||||
logVoidReturn("unloadModel", modelHandle);
|
||||
mEventLogger.enqueue(SessionEvent.createForVoid(
|
||||
UNLOAD_MODEL, modelHandle)
|
||||
.printLog(ALOGI, TAG));
|
||||
} catch (Exception e) {
|
||||
logException("unloadModel", e, modelHandle);
|
||||
mEventLogger.enqueue(SessionEvent.createForException(
|
||||
UNLOAD_MODEL, e, modelHandle)
|
||||
.printLog(ALOGW, TAG));
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
@@ -197,9 +233,13 @@ public class SoundTriggerMiddlewareLogging implements ISoundTriggerMiddlewareInt
|
||||
throws RemoteException {
|
||||
try {
|
||||
mDelegate.startRecognition(modelHandle, config);
|
||||
logVoidReturn("startRecognition", modelHandle, config);
|
||||
mEventLogger.enqueue(SessionEvent.createForVoid(
|
||||
START_RECOGNITION, modelHandle, config)
|
||||
.printLog(ALOGI, TAG));
|
||||
} catch (Exception e) {
|
||||
logException("startRecognition", e, modelHandle, config);
|
||||
mEventLogger.enqueue(SessionEvent.createForException(
|
||||
START_RECOGNITION, e, modelHandle, config)
|
||||
.printLog(ALOGW, TAG));
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
@@ -208,9 +248,13 @@ public class SoundTriggerMiddlewareLogging implements ISoundTriggerMiddlewareInt
|
||||
public void stopRecognition(int modelHandle) throws RemoteException {
|
||||
try {
|
||||
mDelegate.stopRecognition(modelHandle);
|
||||
logVoidReturn("stopRecognition", modelHandle);
|
||||
mEventLogger.enqueue(SessionEvent.createForVoid(
|
||||
STOP_RECOGNITION, modelHandle)
|
||||
.printLog(ALOGI, TAG));
|
||||
} catch (Exception e) {
|
||||
logException("stopRecognition", e, modelHandle);
|
||||
mEventLogger.enqueue(SessionEvent.createForException(
|
||||
STOP_RECOGNITION, e, modelHandle)
|
||||
.printLog(ALOGW, TAG));
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
@@ -219,9 +263,13 @@ public class SoundTriggerMiddlewareLogging implements ISoundTriggerMiddlewareInt
|
||||
public void forceRecognitionEvent(int modelHandle) throws RemoteException {
|
||||
try {
|
||||
mDelegate.forceRecognitionEvent(modelHandle);
|
||||
logVoidReturn("forceRecognitionEvent", modelHandle);
|
||||
mEventLogger.enqueue(SessionEvent.createForVoid(
|
||||
FORCE_RECOGNITION, modelHandle)
|
||||
.printLog(ALOGI, TAG));
|
||||
} catch (Exception e) {
|
||||
logException("forceRecognitionEvent", e, modelHandle);
|
||||
mEventLogger.enqueue(SessionEvent.createForException(
|
||||
FORCE_RECOGNITION, e, modelHandle)
|
||||
.printLog(ALOGW, TAG));
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
@@ -231,9 +279,13 @@ public class SoundTriggerMiddlewareLogging implements ISoundTriggerMiddlewareInt
|
||||
throws RemoteException {
|
||||
try {
|
||||
mDelegate.setModelParameter(modelHandle, modelParam, value);
|
||||
logVoidReturn("setModelParameter", modelHandle, modelParam, value);
|
||||
mEventLogger.enqueue(SessionEvent.createForVoid(
|
||||
SET_MODEL_PARAMETER, modelHandle, modelParam, value)
|
||||
.printLog(ALOGI, TAG));
|
||||
} catch (Exception e) {
|
||||
logException("setModelParameter", e, modelHandle, modelParam, value);
|
||||
mEventLogger.enqueue(SessionEvent.createForException(
|
||||
SET_MODEL_PARAMETER, e, modelHandle, modelParam, value)
|
||||
.printLog(ALOGW, TAG));
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
@@ -242,10 +294,14 @@ public class SoundTriggerMiddlewareLogging implements ISoundTriggerMiddlewareInt
|
||||
public int getModelParameter(int modelHandle, int modelParam) throws RemoteException {
|
||||
try {
|
||||
int result = mDelegate.getModelParameter(modelHandle, modelParam);
|
||||
logReturn("getModelParameter", result, modelHandle, modelParam);
|
||||
mEventLogger.enqueue(SessionEvent.createForReturn(
|
||||
GET_MODEL_PARAMETER, result, modelHandle, modelParam)
|
||||
.printLog(ALOGI, TAG));
|
||||
return result;
|
||||
} catch (Exception e) {
|
||||
logException("getModelParameter", e, modelHandle, modelParam);
|
||||
mEventLogger.enqueue(SessionEvent.createForException(
|
||||
GET_MODEL_PARAMETER, e, modelHandle, modelParam)
|
||||
.printLog(ALOGW, TAG));
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
@@ -256,10 +312,14 @@ public class SoundTriggerMiddlewareLogging implements ISoundTriggerMiddlewareInt
|
||||
try {
|
||||
ModelParameterRange result = mDelegate.queryModelParameterSupport(modelHandle,
|
||||
modelParam);
|
||||
logReturn("queryModelParameterSupport", result, modelHandle, modelParam);
|
||||
mEventLogger.enqueue(SessionEvent.createForReturn(
|
||||
QUERY_MODEL_PARAMETER, result, modelHandle, modelParam)
|
||||
.printLog(ALOGI, TAG));
|
||||
return result;
|
||||
} catch (Exception e) {
|
||||
logException("queryModelParameterSupport", e, modelHandle, modelParam);
|
||||
mEventLogger.enqueue(SessionEvent.createForException(
|
||||
QUERY_MODEL_PARAMETER, e, modelHandle, modelParam)
|
||||
.printLog(ALOGW, TAG));
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
@@ -267,10 +327,20 @@ public class SoundTriggerMiddlewareLogging implements ISoundTriggerMiddlewareInt
|
||||
@Override
|
||||
public void detach() throws RemoteException {
|
||||
try {
|
||||
if (mSessionEventLoggers.remove(mEventLogger)) {
|
||||
while (!mDetachedSessionEventLoggers.offerFirst(mEventLogger)) {
|
||||
// Remove the oldest element, if one still exists
|
||||
mDetachedSessionEventLoggers.pollLast();
|
||||
}
|
||||
}
|
||||
mDelegate.detach();
|
||||
logVoidReturn("detach");
|
||||
mEventLogger.enqueue(SessionEvent.createForVoid(
|
||||
DETACH)
|
||||
.printLog(ALOGI, TAG));
|
||||
} catch (Exception e) {
|
||||
logException("detach", e);
|
||||
mEventLogger.enqueue(SessionEvent.createForException(
|
||||
DETACH, e)
|
||||
.printLog(ALOGW, TAG));
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
@@ -285,107 +355,112 @@ public class SoundTriggerMiddlewareLogging implements ISoundTriggerMiddlewareInt
|
||||
public String toString() {
|
||||
return Objects.toString(mDelegate);
|
||||
}
|
||||
}
|
||||
|
||||
private void logException(String methodName, Exception ex, Object... args) {
|
||||
logExceptionWithObject(this, mOriginatorIdentity, methodName, ex, args);
|
||||
private class CallbackLogging implements ISoundTriggerCallback {
|
||||
private final ISoundTriggerCallback mCallbackDelegate;
|
||||
private final EventLogger mEventLogger;
|
||||
private final Identity mOriginatorIdentity;
|
||||
|
||||
private CallbackLogging(ISoundTriggerCallback delegate,
|
||||
EventLogger eventLogger, Identity originatorIdentity) {
|
||||
mCallbackDelegate = Objects.requireNonNull(delegate);
|
||||
mEventLogger = Objects.requireNonNull(eventLogger);
|
||||
mOriginatorIdentity = originatorIdentity;
|
||||
}
|
||||
|
||||
private void logReturn(String methodName, Object retVal, Object... args) {
|
||||
logReturnWithObject(this, mOriginatorIdentity, methodName, retVal, args);
|
||||
@Override
|
||||
public void onRecognition(int modelHandle, RecognitionEvent event, int captureSession)
|
||||
throws RemoteException {
|
||||
try {
|
||||
mBatteryStatsInternalSupplier.get().noteWakingSoundTrigger(
|
||||
SystemClock.elapsedRealtime(), mOriginatorIdentity.uid);
|
||||
mCallbackDelegate.onRecognition(modelHandle, event, captureSession);
|
||||
mEventLogger.enqueue(SessionEvent.createForVoid(
|
||||
RECOGNITION, modelHandle, event, captureSession)
|
||||
.printLog(ALOGI, TAG));
|
||||
} catch (Exception e) {
|
||||
mEventLogger.enqueue(SessionEvent.createForException(
|
||||
RECOGNITION, e, modelHandle, event, captureSession)
|
||||
.printLog(ALOGW, TAG));
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
private void logVoidReturn(String methodName, Object... args) {
|
||||
logVoidReturnWithObject(this, mOriginatorIdentity, methodName, args);
|
||||
@Override
|
||||
public void onPhraseRecognition(int modelHandle, PhraseRecognitionEvent event,
|
||||
int captureSession)
|
||||
throws RemoteException {
|
||||
try {
|
||||
mBatteryStatsInternalSupplier.get().noteWakingSoundTrigger(
|
||||
SystemClock.elapsedRealtime(), mOriginatorIdentity.uid);
|
||||
startKeyphraseEventLatencyTracking(event);
|
||||
mCallbackDelegate.onPhraseRecognition(modelHandle, event, captureSession);
|
||||
mEventLogger.enqueue(SessionEvent.createForVoid(
|
||||
RECOGNITION, modelHandle, event, captureSession)
|
||||
.printLog(ALOGI, TAG));
|
||||
} catch (Exception e) {
|
||||
mEventLogger.enqueue(SessionEvent.createForException(
|
||||
RECOGNITION, e, modelHandle, event, captureSession)
|
||||
.printLog(ALOGW, TAG));
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
private class CallbackLogging implements ISoundTriggerCallback {
|
||||
private final ISoundTriggerCallback mCallbackDelegate;
|
||||
|
||||
private CallbackLogging(ISoundTriggerCallback delegate) {
|
||||
mCallbackDelegate = delegate;
|
||||
@Override
|
||||
public void onModelUnloaded(int modelHandle) throws RemoteException {
|
||||
try {
|
||||
mCallbackDelegate.onModelUnloaded(modelHandle);
|
||||
mEventLogger.enqueue(SessionEvent.createForVoid(
|
||||
MODEL_UNLOADED, modelHandle)
|
||||
.printLog(ALOGI, TAG));
|
||||
} catch (Exception e) {
|
||||
mEventLogger.enqueue(SessionEvent.createForException(
|
||||
MODEL_UNLOADED, e, modelHandle)
|
||||
.printLog(ALOGW, TAG));
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRecognition(int modelHandle, RecognitionEvent event, int captureSession)
|
||||
throws RemoteException {
|
||||
try {
|
||||
mBatteryStatsInternalSupplier.get().noteWakingSoundTrigger(
|
||||
SystemClock.elapsedRealtime(), mOriginatorIdentity.uid);
|
||||
mCallbackDelegate.onRecognition(modelHandle, event, captureSession);
|
||||
logVoidReturn("onRecognition", modelHandle, event);
|
||||
} catch (Exception e) {
|
||||
logException("onRecognition", e, modelHandle, event);
|
||||
throw e;
|
||||
}
|
||||
@Override
|
||||
public void onResourcesAvailable() throws RemoteException {
|
||||
try {
|
||||
mCallbackDelegate.onResourcesAvailable();
|
||||
mEventLogger.enqueue(SessionEvent.createForVoid(
|
||||
RESOURCES_AVAILABLE)
|
||||
.printLog(ALOGI, TAG));
|
||||
} catch (Exception e) {
|
||||
mEventLogger.enqueue(SessionEvent.createForException(
|
||||
RESOURCES_AVAILABLE, e)
|
||||
.printLog(ALOGW, TAG));
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPhraseRecognition(int modelHandle, PhraseRecognitionEvent event,
|
||||
int captureSession)
|
||||
throws RemoteException {
|
||||
try {
|
||||
mBatteryStatsInternalSupplier.get().noteWakingSoundTrigger(
|
||||
SystemClock.elapsedRealtime(), mOriginatorIdentity.uid);
|
||||
startKeyphraseEventLatencyTracking(event);
|
||||
mCallbackDelegate.onPhraseRecognition(modelHandle, event, captureSession);
|
||||
logVoidReturn("onPhraseRecognition", modelHandle, event);
|
||||
} catch (Exception e) {
|
||||
logException("onPhraseRecognition", e, modelHandle, event);
|
||||
throw e;
|
||||
}
|
||||
@Override
|
||||
public void onModuleDied() throws RemoteException {
|
||||
try {
|
||||
mCallbackDelegate.onModuleDied();
|
||||
mEventLogger.enqueue(SessionEvent.createForVoid(
|
||||
MODULE_DIED)
|
||||
.printLog(ALOGW, TAG));
|
||||
} catch (Exception e) {
|
||||
mEventLogger.enqueue(SessionEvent.createForException(
|
||||
MODULE_DIED, e)
|
||||
.printLog(ALOGW, TAG));
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onModelUnloaded(int modelHandle) throws RemoteException {
|
||||
try {
|
||||
mCallbackDelegate.onModelUnloaded(modelHandle);
|
||||
logVoidReturn("onModelUnloaded", modelHandle);
|
||||
} catch (Exception e) {
|
||||
logException("onModelUnloaded", e, modelHandle);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public IBinder asBinder() {
|
||||
return mCallbackDelegate.asBinder();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResourcesAvailable() throws RemoteException {
|
||||
try {
|
||||
mCallbackDelegate.onResourcesAvailable();
|
||||
logVoidReturn("onResourcesAvailable");
|
||||
} catch (Exception e) {
|
||||
logException("onResourcesAvailable", e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onModuleDied() throws RemoteException {
|
||||
try {
|
||||
mCallbackDelegate.onModuleDied();
|
||||
logVoidReturn("onModuleDied");
|
||||
} catch (Exception e) {
|
||||
logException("onModuleDied", e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
private void logException(String methodName, Exception ex, Object... args) {
|
||||
logExceptionWithObject(this, mOriginatorIdentity, methodName, ex, args);
|
||||
}
|
||||
|
||||
private void logVoidReturn(String methodName, Object... args) {
|
||||
logVoidReturnWithObject(this, mOriginatorIdentity, methodName, args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBinder asBinder() {
|
||||
return mCallbackDelegate.asBinder();
|
||||
}
|
||||
|
||||
// Override toString() in order to have the delegate's ID in it.
|
||||
@Override
|
||||
public String toString() {
|
||||
return Objects.toString(mCallbackDelegate);
|
||||
}
|
||||
// Override toString() in order to have the delegate's ID in it.
|
||||
@Override
|
||||
public String toString() {
|
||||
return Objects.toString(mCallbackDelegate);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -418,105 +493,193 @@ public class SoundTriggerMiddlewareLogging implements ISoundTriggerMiddlewareInt
|
||||
latencyTrackerTag);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Actual logging logic below.
|
||||
private static final int NUM_EVENTS_TO_DUMP = 64;
|
||||
private final static SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("MM-dd HH:mm:ss:SSS");
|
||||
private final @NonNull LinkedList<Event> mLastEvents = new LinkedList<>();
|
||||
|
||||
static private class Event {
|
||||
public final long timestamp = System.currentTimeMillis();
|
||||
public final String message;
|
||||
|
||||
private Event(String message) {
|
||||
this.message = message;
|
||||
}
|
||||
}
|
||||
|
||||
private static String printArgs(@NonNull Object[] args) {
|
||||
StringBuilder result = new StringBuilder();
|
||||
private static StringBuilder printArgs(StringBuilder builder, @NonNull Object[] args) {
|
||||
for (int i = 0; i < args.length; ++i) {
|
||||
if (i > 0) {
|
||||
result.append(", ");
|
||||
builder.append(", ");
|
||||
}
|
||||
printObject(result, args[i]);
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
private static void printObject(@NonNull StringBuilder builder, @Nullable Object obj) {
|
||||
ObjectPrinter.print(builder, obj, 16);
|
||||
}
|
||||
|
||||
private static String printObject(@Nullable Object obj) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
printObject(builder, obj);
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
private void logReturnWithObject(@NonNull Object object, @Nullable Identity originatorIdentity,
|
||||
String methodName,
|
||||
@Nullable Object retVal,
|
||||
@NonNull Object[] args) {
|
||||
final String message = String.format("%s[this=%s, client=%s](%s) -> %s", methodName,
|
||||
object,
|
||||
printObject(originatorIdentity),
|
||||
printArgs(args),
|
||||
printObject(retVal));
|
||||
Slog.i(TAG, message);
|
||||
appendMessage(message);
|
||||
}
|
||||
|
||||
private void logVoidReturnWithObject(@NonNull Object object,
|
||||
@Nullable Identity originatorIdentity, @NonNull String methodName,
|
||||
@NonNull Object[] args) {
|
||||
final String message = String.format("%s[this=%s, client=%s](%s)", methodName,
|
||||
object,
|
||||
printObject(originatorIdentity),
|
||||
printArgs(args));
|
||||
Slog.i(TAG, message);
|
||||
appendMessage(message);
|
||||
}
|
||||
|
||||
private void logExceptionWithObject(@NonNull Object object,
|
||||
@Nullable Identity originatorIdentity, @NonNull String methodName,
|
||||
@NonNull Exception ex,
|
||||
Object[] args) {
|
||||
final String message = String.format("%s[this=%s, client=%s](%s) threw", methodName,
|
||||
object,
|
||||
printObject(originatorIdentity),
|
||||
printArgs(args));
|
||||
Slog.e(TAG, message, ex);
|
||||
appendMessage(message + " " + ex.toString());
|
||||
}
|
||||
|
||||
private void appendMessage(@NonNull String message) {
|
||||
Event event = new Event(message);
|
||||
synchronized (mLastEvents) {
|
||||
if (mLastEvents.size() > NUM_EVENTS_TO_DUMP) {
|
||||
mLastEvents.remove();
|
||||
}
|
||||
mLastEvents.add(event);
|
||||
ObjectPrinter.print(builder, args[i]);
|
||||
}
|
||||
return builder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dump(PrintWriter pw) {
|
||||
pw.println();
|
||||
pw.println("=========================================");
|
||||
pw.println("Last events");
|
||||
pw.println("=========================================");
|
||||
synchronized (mLastEvents) {
|
||||
for (Event event : mLastEvents) {
|
||||
pw.print(DATE_FORMAT.format(new Date(event.timestamp)));
|
||||
pw.print('\t');
|
||||
pw.println(event.message);
|
||||
}
|
||||
// Event loggers
|
||||
pw.println("##Service-Wide logs:");
|
||||
mServiceEventLogger.dump(pw, /* indent = */ " ");
|
||||
|
||||
pw.println("\n##Active Session dumps:\n");
|
||||
for (var sessionLogger : mSessionEventLoggers) {
|
||||
sessionLogger.dump(pw, /* indent= */ " ");
|
||||
pw.println("");
|
||||
}
|
||||
pw.println("##Detached Session dumps:\n");
|
||||
for (var sessionLogger : mDetachedSessionEventLoggers) {
|
||||
sessionLogger.dump(pw, /* indent= */ " ");
|
||||
pw.println("");
|
||||
}
|
||||
pw.println();
|
||||
|
||||
if (mDelegate instanceof Dumpable) {
|
||||
((Dumpable) mDelegate).dump(pw);
|
||||
}
|
||||
}
|
||||
|
||||
public static void printSystemLog(int type, String tag, String message, Exception e) {
|
||||
switch (type) {
|
||||
case Event.ALOGI:
|
||||
Slog.i(tag, message, e);
|
||||
break;
|
||||
case Event.ALOGE:
|
||||
Slog.e(tag, message, e);
|
||||
break;
|
||||
case Event.ALOGW:
|
||||
Slog.w(tag, message, e);
|
||||
break;
|
||||
case Event.ALOGV:
|
||||
default:
|
||||
Slog.v(tag, message, e);
|
||||
}
|
||||
}
|
||||
|
||||
public static class ServiceEvent extends Event {
|
||||
private final Type mType;
|
||||
private final String mPackageName;
|
||||
private final Object mReturnValue;
|
||||
private final Object[] mParams;
|
||||
private final Exception mException;
|
||||
|
||||
public enum Type {
|
||||
ATTACH,
|
||||
LIST_MODULE,
|
||||
}
|
||||
|
||||
public static ServiceEvent createForException(Type type, String packageName,
|
||||
Exception exception, Object... params) {
|
||||
return new ServiceEvent(exception, type, packageName, null, params);
|
||||
}
|
||||
|
||||
public static ServiceEvent createForReturn(Type type, String packageName,
|
||||
Object returnValue, Object... params) {
|
||||
return new ServiceEvent(null , type, packageName, returnValue, params);
|
||||
}
|
||||
|
||||
private ServiceEvent(Exception exception, Type type, String packageName, Object returnValue,
|
||||
Object... params) {
|
||||
mException = exception;
|
||||
mType = type;
|
||||
mPackageName = packageName;
|
||||
mReturnValue = returnValue;
|
||||
mParams = params;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Event printLog(int type, String tag) {
|
||||
printSystemLog(type, tag, eventToString(), mException);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String eventToString() {
|
||||
var sb = new StringBuilder(mType.name()).append(" [client= ");
|
||||
ObjectPrinter.print(sb, mPackageName);
|
||||
sb.append("] (");
|
||||
printArgs(sb, mParams);
|
||||
sb.append(") -> ");
|
||||
if (mException != null) {
|
||||
sb.append("ERROR: ");
|
||||
ObjectPrinter.print(sb, mException);
|
||||
} else {
|
||||
ObjectPrinter.print(sb, mReturnValue);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
||||
public static class SessionEvent extends Event {
|
||||
public enum Type {
|
||||
LOAD_MODEL,
|
||||
LOAD_PHRASE_MODEL,
|
||||
START_RECOGNITION,
|
||||
STOP_RECOGNITION,
|
||||
FORCE_RECOGNITION,
|
||||
UNLOAD_MODEL,
|
||||
GET_MODEL_PARAMETER,
|
||||
SET_MODEL_PARAMETER,
|
||||
QUERY_MODEL_PARAMETER,
|
||||
DETACH,
|
||||
RECOGNITION,
|
||||
MODEL_UNLOADED,
|
||||
MODULE_DIED,
|
||||
RESOURCES_AVAILABLE,
|
||||
}
|
||||
|
||||
private final Type mType;
|
||||
private final Exception mException;
|
||||
private final Object mReturnValue;
|
||||
private final Object[] mParams;
|
||||
|
||||
public static SessionEvent createForException(Type type, Exception exception,
|
||||
Object... params) {
|
||||
return new SessionEvent(exception, type, null, params);
|
||||
}
|
||||
|
||||
public static SessionEvent createForReturn(Type type,
|
||||
Object returnValue, Object... params) {
|
||||
return new SessionEvent(null , type, returnValue, params);
|
||||
}
|
||||
|
||||
public static SessionEvent createForVoid(Type type, Object... params) {
|
||||
return new SessionEvent(null, type, null, params);
|
||||
}
|
||||
|
||||
|
||||
private SessionEvent(Exception exception, Type type, Object returnValue,
|
||||
Object... params) {
|
||||
mException = exception;
|
||||
mType = type;
|
||||
mReturnValue = returnValue;
|
||||
mParams = params;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Event printLog(int type, String tag) {
|
||||
printSystemLog(type, tag, eventToString(), mException);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String eventToString() {
|
||||
var sb = new StringBuilder(mType.name());
|
||||
sb.append(" (");
|
||||
printArgs(sb, mParams);
|
||||
sb.append(")");
|
||||
if (mException != null) {
|
||||
sb.append(" -> ERROR: ");
|
||||
ObjectPrinter.print(sb, mException);
|
||||
} else if (mReturnValue != null) {
|
||||
sb.append(" -> ");
|
||||
ObjectPrinter.print(sb, mReturnValue);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
||||
private static final class ModulePropertySummary {
|
||||
private int mId;
|
||||
private String mImplementor;
|
||||
private int mVersion;
|
||||
|
||||
ModulePropertySummary(int id, String implementor, int version) {
|
||||
mId = id;
|
||||
mImplementor = implementor;
|
||||
mVersion = version;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "{Id: " + mId + ", Implementor: " + mImplementor
|
||||
+ ", Version: " + mVersion + "}";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user