Loading services/core/java/com/android/server/soundtrigger_middleware/Dumpable.java 0 → 100644 +32 −0 Original line number Diff line number Diff line /* * Copyright (C) 2020 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_middleware; import android.annotation.NonNull; import java.io.PrintWriter; /** * An interface of an object that can generate a dump. */ interface Dumpable { /** * Generate a human-readable dump into the given writer. * @param pw The writer. */ void dump(@NonNull PrintWriter pw); } services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareLogging.java +70 −14 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ package com.android.server.soundtrigger_middleware; import android.annotation.NonNull; import android.content.Context; import android.media.soundtrigger_middleware.ISoundTriggerCallback; import android.media.soundtrigger_middleware.ISoundTriggerMiddlewareService; import android.media.soundtrigger_middleware.ISoundTriggerModule; Loading @@ -27,11 +28,16 @@ import android.media.soundtrigger_middleware.RecognitionConfig; import android.media.soundtrigger_middleware.RecognitionEvent; import android.media.soundtrigger_middleware.SoundModel; import android.media.soundtrigger_middleware.SoundTriggerModuleDescriptor; import android.os.Binder; import android.os.IBinder; import android.os.RemoteException; import android.util.Log; import java.io.PrintWriter; import java.text.SimpleDateFormat; import java.util.Arrays; import java.util.Date; import java.util.LinkedList; import java.util.Objects; /** Loading @@ -56,13 +62,11 @@ import java.util.Objects; * String, Object, Object[])}, {@link #logVoidReturnWithObject(Object, String, Object[])} and {@link * #logExceptionWithObject(Object, String, Exception, Object[])}. */ public class SoundTriggerMiddlewareLogging implements ISoundTriggerMiddlewareService { public class SoundTriggerMiddlewareLogging implements ISoundTriggerMiddlewareService, Dumpable { private static final String TAG = "SoundTriggerMiddlewareLogging"; private final @NonNull ISoundTriggerMiddlewareService mDelegate; public SoundTriggerMiddlewareLogging( @NonNull ISoundTriggerMiddlewareService delegate) { public SoundTriggerMiddlewareLogging(@NonNull ISoundTriggerMiddlewareService delegate) { mDelegate = delegate; } Loading Loading @@ -346,6 +350,21 @@ public class SoundTriggerMiddlewareLogging implements ISoundTriggerMiddlewareSer } } //////////////////////////////////////////////////////////////////////////////////////////////// // 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; } } static private String formatArgs(Object[] args) { String result = Arrays.toString(args); // Strip the square brackets. Loading @@ -354,23 +373,60 @@ public class SoundTriggerMiddlewareLogging implements ISoundTriggerMiddlewareSer private void logReturnWithObject(Object object, String methodName, Object retVal, Object[] args) { // TODO(ytai): Save last N entries and emit on dump(). Log.i(TAG, String.format("%s[this=%s](%s) -> %s", methodName, Objects.toString(object), final String message = String.format("%s[this=%s, caller=%d/%d](%s) -> %s", methodName, Objects.toString(object), Binder.getCallingUid(), Binder.getCallingPid(), formatArgs(args), Objects.toString(retVal))); Objects.toString(retVal)); Log.i(TAG, message); appendMessage(message); } private void logVoidReturnWithObject(Object object, String methodName, Object[] args) { // TODO(ytai): Save last N entries and emit on dump(). Log.i(TAG, String.format("%s[this=%s](%s)", methodName, Objects.toString(object), formatArgs(args))); final String message = String.format("%s[this=%s, caller=%d/%d](%s)", methodName, Objects.toString(object), Binder.getCallingUid(), Binder.getCallingPid(), formatArgs(args)); Log.i(TAG, message); appendMessage(message); } private void logExceptionWithObject(Object object, String methodName, Exception ex, Object[] args) { // TODO(ytai): Save last N entries and emit on dump(). Log.e(TAG, String.format("%s[this=%s](%s) threw", methodName, Objects.toString(object), formatArgs(args)), ex); final String message = String.format("%s[this=%s, caller=%d/%d](%s) threw", methodName, Objects.toString(object), Binder.getCallingUid(), Binder.getCallingPid(), formatArgs(args)); Log.e(TAG, message, ex); appendMessage(message + " " + ex.toString()); } private void appendMessage(String message) { Event event = new Event(message); synchronized (mLastEvents) { if (mLastEvents.size() > NUM_EVENTS_TO_DUMP) { mLastEvents.remove(); } mLastEvents.add(event); } } @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); } } pw.println(); if (mDelegate instanceof Dumpable) { ((Dumpable) mDelegate).dump(pw); } } } services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareService.java +8 −0 Original line number Diff line number Diff line Loading @@ -32,6 +32,8 @@ import android.util.Log; import com.android.server.SystemService; import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.Objects; /** Loading Loading @@ -89,6 +91,12 @@ public class SoundTriggerMiddlewareService extends ISoundTriggerMiddlewareServic mDelegate.setExternalCaptureState(active); } @Override protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) { if (mDelegate instanceof Dumpable) { ((Dumpable) mDelegate).dump(fout); } } private final static class ModuleService extends ISoundTriggerModule.Stub { private final ISoundTriggerModule mDelegate; Loading services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareValidation.java +47 −8 Original line number Diff line number Diff line Loading @@ -40,6 +40,7 @@ import android.util.Log; import com.android.internal.util.Preconditions; import java.io.PrintWriter; import java.util.HashMap; import java.util.HashSet; import java.util.Map; Loading Loading @@ -103,12 +104,12 @@ import java.util.Set; * * {@hide} */ public class SoundTriggerMiddlewareValidation implements ISoundTriggerMiddlewareService { public class SoundTriggerMiddlewareValidation implements ISoundTriggerMiddlewareService, Dumpable { private static final String TAG = "SoundTriggerMiddlewareValidation"; private final @NonNull ISoundTriggerMiddlewareService mDelegate; private final @NonNull Context mContext; private Set<Integer> mModuleHandles; private Map<Integer, Set<ModuleService>> mModules; public SoundTriggerMiddlewareValidation( @NonNull ISoundTriggerMiddlewareService delegate, @NonNull Context context) { Loading Loading @@ -154,9 +155,9 @@ public class SoundTriggerMiddlewareValidation implements ISoundTriggerMiddleware // From here on, every exception isn't client's fault. try { SoundTriggerModuleDescriptor[] result = mDelegate.listModules(); mModuleHandles = new HashSet<Integer>(result.length); mModules = new HashMap<>(result.length); for (SoundTriggerModuleDescriptor desc : result) { mModuleHandles.add(desc.handle); mModules.put(desc.handle, new HashSet<>()); } return result; } catch (Exception e) { Loading @@ -176,18 +177,18 @@ public class SoundTriggerMiddlewareValidation implements ISoundTriggerMiddleware synchronized (this) { // State validation. if (mModuleHandles == null) { if (mModules == null) { throw new IllegalStateException( "Client must call listModules() prior to attaching."); } if (!mModuleHandles.contains(handle)) { if (!mModules.containsKey(handle)) { throw new IllegalArgumentException("Invalid handle: " + handle); } // From here on, every exception isn't client's fault. try { ModuleService moduleService = new ModuleService(callback); new ModuleService(handle, callback); moduleService.attach(mDelegate.attach(handle, moduleService)); return moduleService; } catch (Exception e) { Loading Loading @@ -271,6 +272,28 @@ public class SoundTriggerMiddlewareValidation implements ISoundTriggerMiddleware "This implementation is not inteded to be used directly with Binder."); } @Override public void dump(PrintWriter pw) { synchronized (this) { if (mModules != null) { for (int handle : mModules.keySet()) { pw.println("========================================="); pw.printf("Active sessions for module %d", handle); pw.println(); pw.println("========================================="); for (ModuleService session : mModules.get(handle)) { session.dump(pw); } } } } pw.println(); if (mDelegate instanceof Dumpable) { ((Dumpable) mDelegate).dump(pw); } } /** State of a sound model. */ static class ModelState { /** Activity state of a sound model. */ Loading Loading @@ -345,9 +368,11 @@ public class SoundTriggerMiddlewareValidation implements ISoundTriggerMiddleware private final ISoundTriggerCallback mCallback; private ISoundTriggerModule mDelegate; private @NonNull Map<Integer, ModelState> mLoadedModels = new HashMap<>(); private final int mHandle; ModuleService(@NonNull ISoundTriggerCallback callback) { ModuleService(int handle, @NonNull ISoundTriggerCallback callback) { mCallback = callback; mHandle = handle; try { mCallback.asBinder().linkToDeath(null, 0); } catch (RemoteException e) { Loading @@ -357,6 +382,7 @@ public class SoundTriggerMiddlewareValidation implements ISoundTriggerMiddleware void attach(@NonNull ISoundTriggerModule delegate) { mDelegate = delegate; mModules.get(mHandle).add(this); } @Override Loading Loading @@ -652,11 +678,24 @@ public class SoundTriggerMiddlewareValidation implements ISoundTriggerMiddleware mDelegate.detach(); mDelegate = null; mCallback.asBinder().unlinkToDeath(null, 0); mModules.get(mHandle).remove(this); } catch (RemoteException e) { throw e.rethrowAsRuntimeException(); } } void dump(PrintWriter pw) { pw.printf("Loaded models for session %s (handle, active)", toString()); pw.println(); pw.println("-------------------------------"); for (Map.Entry<Integer, ModelState> entry : mLoadedModels.entrySet()) { pw.print(entry.getKey()); pw.print('\t'); pw.print(entry.getValue().activityState.name()); pw.println(); } } //////////////////////////////////////////////////////////////////////////////////////////// // Callbacks Loading Loading
services/core/java/com/android/server/soundtrigger_middleware/Dumpable.java 0 → 100644 +32 −0 Original line number Diff line number Diff line /* * Copyright (C) 2020 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_middleware; import android.annotation.NonNull; import java.io.PrintWriter; /** * An interface of an object that can generate a dump. */ interface Dumpable { /** * Generate a human-readable dump into the given writer. * @param pw The writer. */ void dump(@NonNull PrintWriter pw); }
services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareLogging.java +70 −14 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ package com.android.server.soundtrigger_middleware; import android.annotation.NonNull; import android.content.Context; import android.media.soundtrigger_middleware.ISoundTriggerCallback; import android.media.soundtrigger_middleware.ISoundTriggerMiddlewareService; import android.media.soundtrigger_middleware.ISoundTriggerModule; Loading @@ -27,11 +28,16 @@ import android.media.soundtrigger_middleware.RecognitionConfig; import android.media.soundtrigger_middleware.RecognitionEvent; import android.media.soundtrigger_middleware.SoundModel; import android.media.soundtrigger_middleware.SoundTriggerModuleDescriptor; import android.os.Binder; import android.os.IBinder; import android.os.RemoteException; import android.util.Log; import java.io.PrintWriter; import java.text.SimpleDateFormat; import java.util.Arrays; import java.util.Date; import java.util.LinkedList; import java.util.Objects; /** Loading @@ -56,13 +62,11 @@ import java.util.Objects; * String, Object, Object[])}, {@link #logVoidReturnWithObject(Object, String, Object[])} and {@link * #logExceptionWithObject(Object, String, Exception, Object[])}. */ public class SoundTriggerMiddlewareLogging implements ISoundTriggerMiddlewareService { public class SoundTriggerMiddlewareLogging implements ISoundTriggerMiddlewareService, Dumpable { private static final String TAG = "SoundTriggerMiddlewareLogging"; private final @NonNull ISoundTriggerMiddlewareService mDelegate; public SoundTriggerMiddlewareLogging( @NonNull ISoundTriggerMiddlewareService delegate) { public SoundTriggerMiddlewareLogging(@NonNull ISoundTriggerMiddlewareService delegate) { mDelegate = delegate; } Loading Loading @@ -346,6 +350,21 @@ public class SoundTriggerMiddlewareLogging implements ISoundTriggerMiddlewareSer } } //////////////////////////////////////////////////////////////////////////////////////////////// // 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; } } static private String formatArgs(Object[] args) { String result = Arrays.toString(args); // Strip the square brackets. Loading @@ -354,23 +373,60 @@ public class SoundTriggerMiddlewareLogging implements ISoundTriggerMiddlewareSer private void logReturnWithObject(Object object, String methodName, Object retVal, Object[] args) { // TODO(ytai): Save last N entries and emit on dump(). Log.i(TAG, String.format("%s[this=%s](%s) -> %s", methodName, Objects.toString(object), final String message = String.format("%s[this=%s, caller=%d/%d](%s) -> %s", methodName, Objects.toString(object), Binder.getCallingUid(), Binder.getCallingPid(), formatArgs(args), Objects.toString(retVal))); Objects.toString(retVal)); Log.i(TAG, message); appendMessage(message); } private void logVoidReturnWithObject(Object object, String methodName, Object[] args) { // TODO(ytai): Save last N entries and emit on dump(). Log.i(TAG, String.format("%s[this=%s](%s)", methodName, Objects.toString(object), formatArgs(args))); final String message = String.format("%s[this=%s, caller=%d/%d](%s)", methodName, Objects.toString(object), Binder.getCallingUid(), Binder.getCallingPid(), formatArgs(args)); Log.i(TAG, message); appendMessage(message); } private void logExceptionWithObject(Object object, String methodName, Exception ex, Object[] args) { // TODO(ytai): Save last N entries and emit on dump(). Log.e(TAG, String.format("%s[this=%s](%s) threw", methodName, Objects.toString(object), formatArgs(args)), ex); final String message = String.format("%s[this=%s, caller=%d/%d](%s) threw", methodName, Objects.toString(object), Binder.getCallingUid(), Binder.getCallingPid(), formatArgs(args)); Log.e(TAG, message, ex); appendMessage(message + " " + ex.toString()); } private void appendMessage(String message) { Event event = new Event(message); synchronized (mLastEvents) { if (mLastEvents.size() > NUM_EVENTS_TO_DUMP) { mLastEvents.remove(); } mLastEvents.add(event); } } @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); } } pw.println(); if (mDelegate instanceof Dumpable) { ((Dumpable) mDelegate).dump(pw); } } }
services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareService.java +8 −0 Original line number Diff line number Diff line Loading @@ -32,6 +32,8 @@ import android.util.Log; import com.android.server.SystemService; import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.Objects; /** Loading Loading @@ -89,6 +91,12 @@ public class SoundTriggerMiddlewareService extends ISoundTriggerMiddlewareServic mDelegate.setExternalCaptureState(active); } @Override protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) { if (mDelegate instanceof Dumpable) { ((Dumpable) mDelegate).dump(fout); } } private final static class ModuleService extends ISoundTriggerModule.Stub { private final ISoundTriggerModule mDelegate; Loading
services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareValidation.java +47 −8 Original line number Diff line number Diff line Loading @@ -40,6 +40,7 @@ import android.util.Log; import com.android.internal.util.Preconditions; import java.io.PrintWriter; import java.util.HashMap; import java.util.HashSet; import java.util.Map; Loading Loading @@ -103,12 +104,12 @@ import java.util.Set; * * {@hide} */ public class SoundTriggerMiddlewareValidation implements ISoundTriggerMiddlewareService { public class SoundTriggerMiddlewareValidation implements ISoundTriggerMiddlewareService, Dumpable { private static final String TAG = "SoundTriggerMiddlewareValidation"; private final @NonNull ISoundTriggerMiddlewareService mDelegate; private final @NonNull Context mContext; private Set<Integer> mModuleHandles; private Map<Integer, Set<ModuleService>> mModules; public SoundTriggerMiddlewareValidation( @NonNull ISoundTriggerMiddlewareService delegate, @NonNull Context context) { Loading Loading @@ -154,9 +155,9 @@ public class SoundTriggerMiddlewareValidation implements ISoundTriggerMiddleware // From here on, every exception isn't client's fault. try { SoundTriggerModuleDescriptor[] result = mDelegate.listModules(); mModuleHandles = new HashSet<Integer>(result.length); mModules = new HashMap<>(result.length); for (SoundTriggerModuleDescriptor desc : result) { mModuleHandles.add(desc.handle); mModules.put(desc.handle, new HashSet<>()); } return result; } catch (Exception e) { Loading @@ -176,18 +177,18 @@ public class SoundTriggerMiddlewareValidation implements ISoundTriggerMiddleware synchronized (this) { // State validation. if (mModuleHandles == null) { if (mModules == null) { throw new IllegalStateException( "Client must call listModules() prior to attaching."); } if (!mModuleHandles.contains(handle)) { if (!mModules.containsKey(handle)) { throw new IllegalArgumentException("Invalid handle: " + handle); } // From here on, every exception isn't client's fault. try { ModuleService moduleService = new ModuleService(callback); new ModuleService(handle, callback); moduleService.attach(mDelegate.attach(handle, moduleService)); return moduleService; } catch (Exception e) { Loading Loading @@ -271,6 +272,28 @@ public class SoundTriggerMiddlewareValidation implements ISoundTriggerMiddleware "This implementation is not inteded to be used directly with Binder."); } @Override public void dump(PrintWriter pw) { synchronized (this) { if (mModules != null) { for (int handle : mModules.keySet()) { pw.println("========================================="); pw.printf("Active sessions for module %d", handle); pw.println(); pw.println("========================================="); for (ModuleService session : mModules.get(handle)) { session.dump(pw); } } } } pw.println(); if (mDelegate instanceof Dumpable) { ((Dumpable) mDelegate).dump(pw); } } /** State of a sound model. */ static class ModelState { /** Activity state of a sound model. */ Loading Loading @@ -345,9 +368,11 @@ public class SoundTriggerMiddlewareValidation implements ISoundTriggerMiddleware private final ISoundTriggerCallback mCallback; private ISoundTriggerModule mDelegate; private @NonNull Map<Integer, ModelState> mLoadedModels = new HashMap<>(); private final int mHandle; ModuleService(@NonNull ISoundTriggerCallback callback) { ModuleService(int handle, @NonNull ISoundTriggerCallback callback) { mCallback = callback; mHandle = handle; try { mCallback.asBinder().linkToDeath(null, 0); } catch (RemoteException e) { Loading @@ -357,6 +382,7 @@ public class SoundTriggerMiddlewareValidation implements ISoundTriggerMiddleware void attach(@NonNull ISoundTriggerModule delegate) { mDelegate = delegate; mModules.get(mHandle).add(this); } @Override Loading Loading @@ -652,11 +678,24 @@ public class SoundTriggerMiddlewareValidation implements ISoundTriggerMiddleware mDelegate.detach(); mDelegate = null; mCallback.asBinder().unlinkToDeath(null, 0); mModules.get(mHandle).remove(this); } catch (RemoteException e) { throw e.rethrowAsRuntimeException(); } } void dump(PrintWriter pw) { pw.printf("Loaded models for session %s (handle, active)", toString()); pw.println(); pw.println("-------------------------------"); for (Map.Entry<Integer, ModelState> entry : mLoadedModels.entrySet()) { pw.print(entry.getKey()); pw.print('\t'); pw.print(entry.getValue().activityState.name()); pw.println(); } } //////////////////////////////////////////////////////////////////////////////////////////// // Callbacks Loading