Loading services/core/java/com/android/server/soundtrigger_middleware/ObjectPrinter.java 0 → 100644 +249 −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 android.annotation.Nullable; import java.lang.reflect.Array; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.util.Collection; import java.util.Map; /** * A collection of pretty-print utilities for data objects. */ class ObjectPrinter { /** Default maximum elements to print in a collection. */ static public final int kDefaultMaxCollectionLength = 16; /** * Simple version of {@link #print(Object, boolean, int)} that prints an object, without * recursing into sub-objects. * * @param obj The object to print. * @return A string representing the object. */ static String print(@Nullable Object obj) { return print(obj, false, kDefaultMaxCollectionLength); } /** * Pretty-prints an object. * * @param obj The object to print. * @param deep Whether to pretty-print sub-objects (if false, just prints them * with {@link Object#toString()}). * @param maxCollectionLength Whenever encountering collections, maximum number of elements to * print. * @return A string representing the object. */ static String print(@Nullable Object obj, boolean deep, int maxCollectionLength) { StringBuilder builder = new StringBuilder(); print(builder, obj, deep, maxCollectionLength); return builder.toString(); } /** * This version is suitable for use inside a toString() override of an object, e.g.: * <pre><code> * class MyObject { * ... * @Override * String toString() { * return ObjectPrinter.printPublicFields(this, ...); * } * } * </code></pre> * * @param obj The object to print. * @param deep Whether to pretty-print sub-objects (if false, just prints them * with {@link Object#toString()}). * @param maxCollectionLength Whenever encountering collections, maximum number of elements to * print. */ static String printPublicFields(@Nullable Object obj, boolean deep, int maxCollectionLength) { StringBuilder builder = new StringBuilder(); printPublicFields(builder, obj, deep, maxCollectionLength); return builder.toString(); } /** * A version of {@link #print(Object, boolean, int)} that uses a {@link StringBuilder}. * * @param builder StringBuilder to print into. * @param obj The object to print. * @param deep Whether to pretty-print sub-objects (if false, just prints them * with {@link Object#toString()}). * @param maxCollectionLength Whenever encountering collections, maximum number of elements to * print. */ static void print(@NonNull StringBuilder builder, @Nullable Object obj, boolean deep, int maxCollectionLength) { try { if (obj == null) { builder.append("null"); return; } if (obj instanceof Boolean) { builder.append(obj.toString()); return; } if (obj instanceof Number) { builder.append(obj.toString()); return; } if (obj instanceof Character) { builder.append('\''); builder.append(obj.toString()); builder.append('\''); return; } if (obj instanceof String) { builder.append('"'); builder.append(obj.toString()); builder.append('"'); return; } Class cls = obj.getClass(); if (Collection.class.isAssignableFrom(cls)) { Collection collection = (Collection) obj; builder.append("[ "); int length = collection.size(); boolean isLong = false; int i = 0; for (Object child : collection) { if (i > 0) { builder.append(", "); } if (i >= maxCollectionLength) { isLong = true; break; } print(builder, child, deep, maxCollectionLength); ++i; } if (isLong) { builder.append("... (+"); builder.append(length - maxCollectionLength); builder.append(" entries)"); } builder.append(" ]"); return; } if (Map.class.isAssignableFrom(cls)) { Map<?, ?> map = (Map<?, ?>) obj; builder.append("< "); int length = map.size(); boolean isLong = false; int i = 0; for (Map.Entry<?, ?> child : map.entrySet()) { if (i > 0) { builder.append(", "); } if (i >= maxCollectionLength) { isLong = true; break; } print(builder, child.getKey(), deep, maxCollectionLength); builder.append(": "); print(builder, child.getValue(), deep, maxCollectionLength); ++i; } if (isLong) { builder.append("... (+"); builder.append(length - maxCollectionLength); builder.append(" entries)"); } builder.append(" >"); return; } if (cls.isArray()) { builder.append("[ "); int length = Array.getLength(obj); boolean isLong = false; for (int i = 0; i < length; ++i) { if (i > 0) { builder.append(", "); } if (i >= maxCollectionLength) { isLong = true; break; } print(builder, Array.get(obj, i), deep, maxCollectionLength); } if (isLong) { builder.append("... (+"); builder.append(length - maxCollectionLength); builder.append(" entries)"); } builder.append(" ]"); return; } if (!deep) { builder.append(obj.toString()); return; } printPublicFields(builder, obj, deep, maxCollectionLength); } catch (Exception e) { throw new RuntimeException(e); } } /** * A version of {@link #printPublicFields(Object, boolean, int)} that uses a {@link * StringBuilder}. * * @param obj The object to print. * @param deep Whether to pretty-print sub-objects (if false, just prints them * with {@link Object#toString()}). * @param maxCollectionLength Whenever encountering collections, maximum number of elements to * print. */ static void printPublicFields(@NonNull StringBuilder builder, @Nullable Object obj, boolean deep, int maxCollectionLength) { try { Class cls = obj.getClass(); builder.append("{ "); boolean first = true; for (Field fld : cls.getDeclaredFields()) { int mod = fld.getModifiers(); if ((mod & Modifier.PUBLIC) != 0 && (mod & Modifier.STATIC) == 0) { if (first) { first = false; } else { builder.append(", "); } builder.append(fld.getName()); builder.append(": "); print(builder, fld.get(obj), deep, maxCollectionLength); } } builder.append(" }"); } catch (Exception e) { throw new RuntimeException(e); } } } services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareLogging.java +40 −18 Original line number Diff line number Diff line Loading @@ -17,7 +17,7 @@ package com.android.server.soundtrigger_middleware; import android.annotation.NonNull; import android.content.Context; import android.annotation.Nullable; import android.media.soundtrigger_middleware.ISoundTriggerCallback; import android.media.soundtrigger_middleware.ISoundTriggerMiddlewareService; import android.media.soundtrigger_middleware.ISoundTriggerModule; Loading @@ -30,6 +30,7 @@ import android.media.soundtrigger_middleware.SoundModel; import android.media.soundtrigger_middleware.SoundTriggerModuleDescriptor; import android.os.Binder; import android.os.IBinder; import android.os.Parcelable; import android.os.RemoteException; import android.util.Log; Loading @@ -38,7 +39,6 @@ import java.text.SimpleDateFormat; import java.util.Arrays; import java.util.Date; import java.util.LinkedList; import java.util.Objects; /** * An ISoundTriggerMiddlewareService decorator, which adds logging of all API calls (and Loading Loading @@ -365,43 +365,65 @@ public class SoundTriggerMiddlewareLogging implements ISoundTriggerMiddlewareSer } } static private String formatArgs(Object[] args) { String result = Arrays.toString(args); // Strip the square brackets. return result.substring(1, result.length() - 1); private static String printArgs(@NonNull Object[] args) { StringBuilder result = new StringBuilder(); for (int i = 0; i < args.length; ++i) { if (i > 0) { result.append(", "); } printObject(result, args[i]); } return result.toString(); } private void logReturnWithObject(Object object, String methodName, Object retVal, Object[] args) { private static void printObject(@NonNull StringBuilder builder, @Nullable Object obj) { if (obj instanceof Parcelable) { ObjectPrinter.print(builder, obj, true, 16); } else { builder.append(obj.toString()); } } private static String printObject(@Nullable Object obj) { StringBuilder builder = new StringBuilder(); printObject(builder, obj); return builder.toString(); } private void logReturnWithObject(@NonNull Object object, String methodName, @Nullable Object retVal, @NonNull Object[] args) { final String message = String.format("%s[this=%s, caller=%d/%d](%s) -> %s", methodName, Objects.toString(object), object, Binder.getCallingUid(), Binder.getCallingPid(), formatArgs(args), Objects.toString(retVal)); printArgs(args), printObject(retVal)); Log.i(TAG, message); appendMessage(message); } private void logVoidReturnWithObject(Object object, String methodName, Object[] args) { private void logVoidReturnWithObject(@NonNull Object object, @NonNull String methodName, @NonNull Object[] args) { final String message = String.format("%s[this=%s, caller=%d/%d](%s)", methodName, Objects.toString(object), object, Binder.getCallingUid(), Binder.getCallingPid(), formatArgs(args)); printArgs(args)); Log.i(TAG, message); appendMessage(message); } private void logExceptionWithObject(Object object, String methodName, Exception ex, private void logExceptionWithObject(@NonNull Object object, @NonNull String methodName, @NonNull Exception ex, Object[] args) { final String message = String.format("%s[this=%s, caller=%d/%d](%s) threw", methodName, Objects.toString(object), object, Binder.getCallingUid(), Binder.getCallingPid(), formatArgs(args)); printArgs(args)); Log.e(TAG, message, ex); appendMessage(message + " " + ex.toString()); } private void appendMessage(String message) { private void appendMessage(@NonNull String message) { Event event = new Event(message); synchronized (mLastEvents) { if (mLastEvents.size() > NUM_EVENTS_TO_DUMP) { Loading Loading
services/core/java/com/android/server/soundtrigger_middleware/ObjectPrinter.java 0 → 100644 +249 −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 android.annotation.Nullable; import java.lang.reflect.Array; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.util.Collection; import java.util.Map; /** * A collection of pretty-print utilities for data objects. */ class ObjectPrinter { /** Default maximum elements to print in a collection. */ static public final int kDefaultMaxCollectionLength = 16; /** * Simple version of {@link #print(Object, boolean, int)} that prints an object, without * recursing into sub-objects. * * @param obj The object to print. * @return A string representing the object. */ static String print(@Nullable Object obj) { return print(obj, false, kDefaultMaxCollectionLength); } /** * Pretty-prints an object. * * @param obj The object to print. * @param deep Whether to pretty-print sub-objects (if false, just prints them * with {@link Object#toString()}). * @param maxCollectionLength Whenever encountering collections, maximum number of elements to * print. * @return A string representing the object. */ static String print(@Nullable Object obj, boolean deep, int maxCollectionLength) { StringBuilder builder = new StringBuilder(); print(builder, obj, deep, maxCollectionLength); return builder.toString(); } /** * This version is suitable for use inside a toString() override of an object, e.g.: * <pre><code> * class MyObject { * ... * @Override * String toString() { * return ObjectPrinter.printPublicFields(this, ...); * } * } * </code></pre> * * @param obj The object to print. * @param deep Whether to pretty-print sub-objects (if false, just prints them * with {@link Object#toString()}). * @param maxCollectionLength Whenever encountering collections, maximum number of elements to * print. */ static String printPublicFields(@Nullable Object obj, boolean deep, int maxCollectionLength) { StringBuilder builder = new StringBuilder(); printPublicFields(builder, obj, deep, maxCollectionLength); return builder.toString(); } /** * A version of {@link #print(Object, boolean, int)} that uses a {@link StringBuilder}. * * @param builder StringBuilder to print into. * @param obj The object to print. * @param deep Whether to pretty-print sub-objects (if false, just prints them * with {@link Object#toString()}). * @param maxCollectionLength Whenever encountering collections, maximum number of elements to * print. */ static void print(@NonNull StringBuilder builder, @Nullable Object obj, boolean deep, int maxCollectionLength) { try { if (obj == null) { builder.append("null"); return; } if (obj instanceof Boolean) { builder.append(obj.toString()); return; } if (obj instanceof Number) { builder.append(obj.toString()); return; } if (obj instanceof Character) { builder.append('\''); builder.append(obj.toString()); builder.append('\''); return; } if (obj instanceof String) { builder.append('"'); builder.append(obj.toString()); builder.append('"'); return; } Class cls = obj.getClass(); if (Collection.class.isAssignableFrom(cls)) { Collection collection = (Collection) obj; builder.append("[ "); int length = collection.size(); boolean isLong = false; int i = 0; for (Object child : collection) { if (i > 0) { builder.append(", "); } if (i >= maxCollectionLength) { isLong = true; break; } print(builder, child, deep, maxCollectionLength); ++i; } if (isLong) { builder.append("... (+"); builder.append(length - maxCollectionLength); builder.append(" entries)"); } builder.append(" ]"); return; } if (Map.class.isAssignableFrom(cls)) { Map<?, ?> map = (Map<?, ?>) obj; builder.append("< "); int length = map.size(); boolean isLong = false; int i = 0; for (Map.Entry<?, ?> child : map.entrySet()) { if (i > 0) { builder.append(", "); } if (i >= maxCollectionLength) { isLong = true; break; } print(builder, child.getKey(), deep, maxCollectionLength); builder.append(": "); print(builder, child.getValue(), deep, maxCollectionLength); ++i; } if (isLong) { builder.append("... (+"); builder.append(length - maxCollectionLength); builder.append(" entries)"); } builder.append(" >"); return; } if (cls.isArray()) { builder.append("[ "); int length = Array.getLength(obj); boolean isLong = false; for (int i = 0; i < length; ++i) { if (i > 0) { builder.append(", "); } if (i >= maxCollectionLength) { isLong = true; break; } print(builder, Array.get(obj, i), deep, maxCollectionLength); } if (isLong) { builder.append("... (+"); builder.append(length - maxCollectionLength); builder.append(" entries)"); } builder.append(" ]"); return; } if (!deep) { builder.append(obj.toString()); return; } printPublicFields(builder, obj, deep, maxCollectionLength); } catch (Exception e) { throw new RuntimeException(e); } } /** * A version of {@link #printPublicFields(Object, boolean, int)} that uses a {@link * StringBuilder}. * * @param obj The object to print. * @param deep Whether to pretty-print sub-objects (if false, just prints them * with {@link Object#toString()}). * @param maxCollectionLength Whenever encountering collections, maximum number of elements to * print. */ static void printPublicFields(@NonNull StringBuilder builder, @Nullable Object obj, boolean deep, int maxCollectionLength) { try { Class cls = obj.getClass(); builder.append("{ "); boolean first = true; for (Field fld : cls.getDeclaredFields()) { int mod = fld.getModifiers(); if ((mod & Modifier.PUBLIC) != 0 && (mod & Modifier.STATIC) == 0) { if (first) { first = false; } else { builder.append(", "); } builder.append(fld.getName()); builder.append(": "); print(builder, fld.get(obj), deep, maxCollectionLength); } } builder.append(" }"); } catch (Exception e) { throw new RuntimeException(e); } } }
services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareLogging.java +40 −18 Original line number Diff line number Diff line Loading @@ -17,7 +17,7 @@ package com.android.server.soundtrigger_middleware; import android.annotation.NonNull; import android.content.Context; import android.annotation.Nullable; import android.media.soundtrigger_middleware.ISoundTriggerCallback; import android.media.soundtrigger_middleware.ISoundTriggerMiddlewareService; import android.media.soundtrigger_middleware.ISoundTriggerModule; Loading @@ -30,6 +30,7 @@ import android.media.soundtrigger_middleware.SoundModel; import android.media.soundtrigger_middleware.SoundTriggerModuleDescriptor; import android.os.Binder; import android.os.IBinder; import android.os.Parcelable; import android.os.RemoteException; import android.util.Log; Loading @@ -38,7 +39,6 @@ import java.text.SimpleDateFormat; import java.util.Arrays; import java.util.Date; import java.util.LinkedList; import java.util.Objects; /** * An ISoundTriggerMiddlewareService decorator, which adds logging of all API calls (and Loading Loading @@ -365,43 +365,65 @@ public class SoundTriggerMiddlewareLogging implements ISoundTriggerMiddlewareSer } } static private String formatArgs(Object[] args) { String result = Arrays.toString(args); // Strip the square brackets. return result.substring(1, result.length() - 1); private static String printArgs(@NonNull Object[] args) { StringBuilder result = new StringBuilder(); for (int i = 0; i < args.length; ++i) { if (i > 0) { result.append(", "); } printObject(result, args[i]); } return result.toString(); } private void logReturnWithObject(Object object, String methodName, Object retVal, Object[] args) { private static void printObject(@NonNull StringBuilder builder, @Nullable Object obj) { if (obj instanceof Parcelable) { ObjectPrinter.print(builder, obj, true, 16); } else { builder.append(obj.toString()); } } private static String printObject(@Nullable Object obj) { StringBuilder builder = new StringBuilder(); printObject(builder, obj); return builder.toString(); } private void logReturnWithObject(@NonNull Object object, String methodName, @Nullable Object retVal, @NonNull Object[] args) { final String message = String.format("%s[this=%s, caller=%d/%d](%s) -> %s", methodName, Objects.toString(object), object, Binder.getCallingUid(), Binder.getCallingPid(), formatArgs(args), Objects.toString(retVal)); printArgs(args), printObject(retVal)); Log.i(TAG, message); appendMessage(message); } private void logVoidReturnWithObject(Object object, String methodName, Object[] args) { private void logVoidReturnWithObject(@NonNull Object object, @NonNull String methodName, @NonNull Object[] args) { final String message = String.format("%s[this=%s, caller=%d/%d](%s)", methodName, Objects.toString(object), object, Binder.getCallingUid(), Binder.getCallingPid(), formatArgs(args)); printArgs(args)); Log.i(TAG, message); appendMessage(message); } private void logExceptionWithObject(Object object, String methodName, Exception ex, private void logExceptionWithObject(@NonNull Object object, @NonNull String methodName, @NonNull Exception ex, Object[] args) { final String message = String.format("%s[this=%s, caller=%d/%d](%s) threw", methodName, Objects.toString(object), object, Binder.getCallingUid(), Binder.getCallingPid(), formatArgs(args)); printArgs(args)); Log.e(TAG, message, ex); appendMessage(message + " " + ex.toString()); } private void appendMessage(String message) { private void appendMessage(@NonNull String message) { Event event = new Event(message); synchronized (mLastEvents) { if (mLastEvents.size() > NUM_EVENTS_TO_DUMP) { Loading