From e788a3e16ad86ea9439a8c5c0187f270b2e69490 Mon Sep 17 00:00:00 2001 From: Ytai Ben-Tsvi Date: Tue, 28 Dec 2021 12:37:53 -0800 Subject: [PATCH] Avoid reflection in ObjectPrinter This works around the fact that the Android toolchain may now increase the visibility of fields, so a field being public is not a good signal for whether it should be printed. Replaced object printing with toString() for composite objects, relying on the auto-generated printer for AIDL objects. In the process, cleaned-up a bunch of unused methods / arguments and lint warnings. Bug: 210901706 Test: Manual verification of STMW logs and dumpsys Change-Id: I839e3830e9378ecf8fca9d4d0d3fdcffe00c0c6c --- .../ObjectPrinter.java | 106 ++---------------- .../SoundTriggerMiddlewareLogging.java | 6 +- .../SoundTriggerMiddlewarePermission.java | 11 +- .../SoundTriggerMiddlewareValidation.java | 14 +-- 4 files changed, 27 insertions(+), 110 deletions(-) diff --git a/services/core/java/com/android/server/soundtrigger_middleware/ObjectPrinter.java b/services/core/java/com/android/server/soundtrigger_middleware/ObjectPrinter.java index 7f047f8821226..fba0fb49da5cd 100644 --- a/services/core/java/com/android/server/soundtrigger_middleware/ObjectPrinter.java +++ b/services/core/java/com/android/server/soundtrigger_middleware/ObjectPrinter.java @@ -20,8 +20,6 @@ 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; @@ -32,68 +30,29 @@ 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) { + static String print(@Nullable Object obj, int maxCollectionLength) { StringBuilder builder = new StringBuilder(); - print(builder, obj, deep, maxCollectionLength); + print(builder, obj, maxCollectionLength); return builder.toString(); } /** - * This version is suitable for use inside a toString() override of an object, e.g.: - *

-     *     class MyObject {
-     *         ...
-     *         @Override
-     *         String toString() {
-     *             return ObjectPrinter.printPublicFields(this, ...);
-     *         }
-     *     }
-     * 
- * - * @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}. + * A version of {@link #print(Object, 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, + static void print(@NonNull StringBuilder builder, @Nullable Object obj, int maxCollectionLength) { try { if (obj == null) { @@ -101,16 +60,16 @@ class ObjectPrinter { return; } if (obj instanceof Boolean) { - builder.append(obj.toString()); + builder.append(obj); return; } if (obj instanceof Number) { - builder.append(obj.toString()); + builder.append(obj); return; } if (obj instanceof Character) { builder.append('\''); - builder.append(obj.toString()); + builder.append(obj); builder.append('\''); return; } @@ -137,7 +96,7 @@ class ObjectPrinter { isLong = true; break; } - print(builder, child, deep, maxCollectionLength); + print(builder, child, maxCollectionLength); ++i; } if (isLong) { @@ -163,9 +122,9 @@ class ObjectPrinter { isLong = true; break; } - print(builder, child.getKey(), deep, maxCollectionLength); + print(builder, child.getKey(), maxCollectionLength); builder.append(": "); - print(builder, child.getValue(), deep, maxCollectionLength); + print(builder, child.getValue(), maxCollectionLength); ++i; } if (isLong) { @@ -189,7 +148,7 @@ class ObjectPrinter { isLong = true; break; } - print(builder, Array.get(obj, i), deep, maxCollectionLength); + print(builder, Array.get(obj, i), maxCollectionLength); } if (isLong) { builder.append("... (+"); @@ -200,48 +159,7 @@ class ObjectPrinter { 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(" }"); + builder.append(obj); } catch (Exception e) { throw new RuntimeException(e); } diff --git a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareLogging.java b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareLogging.java index 559e777a8c0ec..dc4bdaaa81584 100644 --- a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareLogging.java +++ b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareLogging.java @@ -18,14 +18,14 @@ package com.android.server.soundtrigger_middleware; import android.annotation.NonNull; import android.annotation.Nullable; +import android.media.permission.Identity; +import android.media.permission.IdentityContext; import android.media.soundtrigger.ModelParameterRange; import android.media.soundtrigger.PhraseRecognitionEvent; import android.media.soundtrigger.PhraseSoundModel; import android.media.soundtrigger.RecognitionConfig; import android.media.soundtrigger.RecognitionEvent; import android.media.soundtrigger.SoundModel; -import android.media.permission.Identity; -import android.media.permission.IdentityContext; import android.media.soundtrigger_middleware.ISoundTriggerCallback; import android.media.soundtrigger_middleware.ISoundTriggerModule; import android.media.soundtrigger_middleware.SoundTriggerModuleDescriptor; @@ -387,7 +387,7 @@ public class SoundTriggerMiddlewareLogging implements ISoundTriggerMiddlewareInt } private static void printObject(@NonNull StringBuilder builder, @Nullable Object obj) { - ObjectPrinter.print(builder, obj, true, 16); + ObjectPrinter.print(builder, obj, 16); } private static String printObject(@Nullable Object obj) { diff --git a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewarePermission.java b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewarePermission.java index 76927e15a0f7f..f3d151fe5cc4f 100644 --- a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewarePermission.java +++ b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewarePermission.java @@ -21,9 +21,11 @@ import static android.Manifest.permission.RECORD_AUDIO; import android.annotation.NonNull; import android.annotation.Nullable; -import android.app.AppOpsManager; import android.content.Context; import android.content.PermissionChecker; +import android.media.permission.Identity; +import android.media.permission.IdentityContext; +import android.media.permission.PermissionUtil; import android.media.soundtrigger.ModelParameterRange; import android.media.soundtrigger.PhraseRecognitionEvent; import android.media.soundtrigger.PhraseSoundModel; @@ -31,9 +33,6 @@ import android.media.soundtrigger.RecognitionConfig; import android.media.soundtrigger.RecognitionEvent; import android.media.soundtrigger.SoundModel; import android.media.soundtrigger.Status; -import android.media.permission.Identity; -import android.media.permission.IdentityContext; -import android.media.permission.PermissionUtil; import android.media.soundtrigger_middleware.ISoundTriggerCallback; import android.media.soundtrigger_middleware.ISoundTriggerMiddlewareService; import android.media.soundtrigger_middleware.ISoundTriggerModule; @@ -144,7 +143,7 @@ public class SoundTriggerMiddlewarePermission implements ISoundTriggerMiddleware if (status != PermissionChecker.PERMISSION_GRANTED) { throw new SecurityException( String.format("Failed to obtain permission %s for identity %s", permission, - ObjectPrinter.print(identity, true, 16))); + ObjectPrinter.print(identity, 16))); } } @@ -168,7 +167,7 @@ public class SoundTriggerMiddlewarePermission implements ISoundTriggerMiddleware case PermissionChecker.PERMISSION_HARD_DENIED: throw new SecurityException( String.format("Failed to obtain permission %s for identity %s", permission, - ObjectPrinter.print(identity, true, 16))); + ObjectPrinter.print(identity, 16))); default: throw new RuntimeException("Unexpected perimission check result."); } diff --git a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareValidation.java b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareValidation.java index 4243fc775ef67..09035cd1d165e 100644 --- a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareValidation.java +++ b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareValidation.java @@ -18,6 +18,8 @@ package com.android.server.soundtrigger_middleware; import android.annotation.NonNull; import android.annotation.Nullable; +import android.media.permission.Identity; +import android.media.permission.IdentityContext; import android.media.soundtrigger.ModelParameterRange; import android.media.soundtrigger.PhraseRecognitionEvent; import android.media.soundtrigger.PhraseSoundModel; @@ -27,8 +29,6 @@ import android.media.soundtrigger.RecognitionEvent; import android.media.soundtrigger.RecognitionStatus; import android.media.soundtrigger.SoundModel; import android.media.soundtrigger.Status; -import android.media.permission.Identity; -import android.media.permission.IdentityContext; import android.media.soundtrigger_middleware.ISoundTriggerCallback; import android.media.soundtrigger_middleware.ISoundTriggerMiddlewareService; import android.media.soundtrigger_middleware.ISoundTriggerModule; @@ -230,7 +230,7 @@ public class SoundTriggerMiddlewareValidation implements ISoundTriggerMiddleware final ModuleState module = mModules.get(handle); pw.println("========================================="); pw.printf("Module %d\n%s\n", handle, - ObjectPrinter.print(module.properties, true, 16)); + ObjectPrinter.print(module.properties, 16)); pw.println("========================================="); for (Session session : module.sessions) { session.dump(pw); @@ -250,11 +250,11 @@ public class SoundTriggerMiddlewareValidation implements ISoundTriggerMiddleware /** State of a sound model. */ static class ModelState { ModelState(SoundModel model) { - this.description = ObjectPrinter.print(model, true, 16); + this.description = ObjectPrinter.print(model, 16); } ModelState(PhraseSoundModel model) { - this.description = ObjectPrinter.print(model, true, 16); + this.description = ObjectPrinter.print(model, 16); } /** Activity state of a sound model. */ @@ -690,8 +690,8 @@ public class SoundTriggerMiddlewareValidation implements ISoundTriggerMiddleware if (mState == ModuleStatus.ALIVE) { pw.println("-------------------------------"); pw.printf("Session %s, client: %s\n", toString(), - ObjectPrinter.print(mOriginatorIdentity, true, 16)); - pw.printf("Loaded models (handle, active, description):", toString()); + ObjectPrinter.print(mOriginatorIdentity, 16)); + pw.println("Loaded models (handle, active, description):"); pw.println(); pw.println("-------------------------------"); for (Map.Entry entry : mLoadedModels.entrySet()) {