diff options
| author | Android (Google) Code Review <android-gerrit@google.com> | 2009-05-04 14:03:40 -0700 |
|---|---|---|
| committer | Android (Google) Code Review <android-gerrit@google.com> | 2009-05-04 14:03:40 -0700 |
| commit | 7ff943673e48a912eb7cc5add08e206c2c25d68e (patch) | |
| tree | a529f5fea2ba25fb8fa2fc17c2b4737f36d8bbcc | |
| parent | 5c6f93f1422647c7f914a15bfad00992685c3eac (diff) | |
| parent | 1ce5bd34632e91a928aa12a30b1c160a35db033b (diff) | |
| download | frameworks_base-7ff943673e48a912eb7cc5add08e206c2c25d68e.zip frameworks_base-7ff943673e48a912eb7cc5add08e206c2c25d68e.tar.gz frameworks_base-7ff943673e48a912eb7cc5add08e206c2c25d68e.tar.bz2 | |
Merge change 911 into donut
* changes:
Debug: Add setPropertiesOn(), and @hide it for now
| -rw-r--r-- | core/java/android/os/Debug.java | 204 |
1 files changed, 203 insertions, 1 deletions
diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java index 5ea5aae..1b4b56b 100644 --- a/core/java/android/os/Debug.java +++ b/core/java/android/os/Debug.java @@ -16,10 +16,20 @@ package android.os; +import com.android.internal.util.TypedProperties; + +import android.util.Config; +import android.util.Log; + +import java.io.FileNotFoundException; import java.io.FileOutputStream; +import java.io.FileReader; import java.io.IOException; import java.io.OutputStreamWriter; import java.io.PrintWriter; +import java.io.Reader; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; import org.apache.harmony.dalvik.ddmc.Chunk; import org.apache.harmony.dalvik.ddmc.ChunkHandler; @@ -721,5 +731,197 @@ href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Lo count += mCounts[Opcodes.OP_INVOKE_SUPER_QUICK_RANGE]; return count; } - }; + } + + + /** + * A Map of typed debug properties. + */ + private static final TypedProperties debugProperties; + + /* + * Load the debug properties from the standard files into debugProperties. + */ + static { + if (Config.DEBUG) { + final String TAG = "DebugProperties"; + final String[] files = { "/system/debug.prop", "/debug.prop", "/data/debug.prop" }; + final TypedProperties tp = new TypedProperties(); + + // Read the properties from each of the files, if present. + for (String file: files) { + Reader r; + try { + r = new FileReader(file); + } catch (FileNotFoundException ex) { + // It's ok if a file is missing. + continue; + } + + Exception failure = null; + try { + tp.load(r); + } catch (IOException ex) { + failure = ex; + } catch (TypedProperties.ParseException ex) { + failure = ex; + } + if (failure != null) { + throw new RuntimeException("Problem loading " + file, failure); + } + } + + debugProperties = tp.isEmpty() ? null : tp; + } else { + debugProperties = null; + } + } + + + /** + * Returns true if the type of the field matches the specified class. + * Handles the case where the class is, e.g., java.lang.Boolean, but + * the field is of the primitive "boolean" type. Also handles all of + * the java.lang.Number subclasses. + */ + private static boolean fieldTypeMatches(Field field, Class<?> cl) { + Class<?> fieldClass = field.getType(); + if (fieldClass == cl) { + return true; + } + Field primitiveTypeField; + try { + /* All of the classes we care about (Boolean, Integer, etc.) + * have a Class field called "TYPE" that points to the corresponding + * primitive class. + */ + primitiveTypeField = cl.getField("TYPE"); + } catch (NoSuchFieldException ex) { + return false; + } + try { + return fieldClass == (Class<?>)primitiveTypeField.get(null); + } catch (IllegalAccessException ex) { + return false; + } + } + + + /** + * Looks up the property that corresponds to the field, and sets the field's value + * if the types match. + */ + private static void modifyFieldIfSet(final Field field, final String propertyName) { + if (field.getType() == java.lang.String.class) { + int stringInfo = debugProperties.getStringInfo(propertyName); + switch (stringInfo) { + case TypedProperties.STRING_SET: + // Handle as usual below. + break; + case TypedProperties.STRING_NULL: + try { + field.set(null, null); // null object for static fields; null string + } catch (IllegalAccessException ex) { + throw new IllegalArgumentException( + "Cannot set field for " + propertyName, ex); + } + return; + case TypedProperties.STRING_NOT_SET: + return; + case TypedProperties.STRING_TYPE_MISMATCH: + throw new IllegalArgumentException( + "Type of " + propertyName + " " + + " does not match field type (" + field.getType() + ")"); + default: + throw new IllegalStateException( + "Unexpected getStringInfo(" + propertyName + ") return value " + + stringInfo); + } + } + Object value = debugProperties.get(propertyName); + if (value != null) { + if (!fieldTypeMatches(field, value.getClass())) { + throw new IllegalArgumentException( + "Type of " + propertyName + " (" + value.getClass() + ") " + + " does not match field type (" + field.getType() + ")"); + } + try { + field.set(null, value); // null object for static fields + } catch (IllegalAccessException ex) { + throw new IllegalArgumentException( + "Cannot set field for " + propertyName, ex); + } + } + } + + + /** + * Reflectively sets static fields of a class based on internal debugging + * properties. This method is a no-op if android.util.Config.DEBUG is + * false. + * <p> + * <strong>NOTE TO APPLICATION DEVELOPERS</strong>: Config.DEBUG will + * always be false in release builds. This API is typically only useful + * for platform developers. + * </p> + * Class setup: define a class whose only fields are non-final, static + * primitive types (except for "char") or Strings. In a static block + * after the field definitions/initializations, pass the class to + * this method, Debug.setPropertiesOn(). Example: + * <pre> + * package com.example; + * + * import android.os.Debug; + * + * public class MyDebugVars { + * public static String s = "a string"; + * public static String s2 = "second string"; + * public static String ns = null; + * public static boolean b = false; + * public static int i = 5; + * public static float f = 0.1f; + * public static double d = 0.5d; + * + * // This MUST appear AFTER all fields are defined and initialized! + * static { + * Debug.setPropertiesOn(MyDebugVars.class); + * } + * } + * </pre> + * setPropertiesOn() may override the value of any field in the class based + * on internal properties that are fixed at boot time. + * <p> + * These properties are only set during platform debugging, and are not + * meant to be used as a general-purpose properties store. + * + * {@hide} + * + * @param cl The class to (possibly) modify + * @throws IllegalArgumentException if any fields are final or non-static, + * or if the type of the field does not match the type of + * the internal debugging property value. + */ + public static void setPropertiesOn(Class<?> cl) { + if (Config.DEBUG) { + if (debugProperties != null) { + /* Only look for fields declared directly by the class, + * so we don't mysteriously change static fields in superclasses. + */ + for (Field field : cl.getDeclaredFields()) { + final String propertyName = cl.getName() + "." + field.getName(); + boolean isStatic = Modifier.isStatic(field.getModifiers()); + boolean isFinal = Modifier.isFinal(field.getModifiers()); + if (!isStatic || isFinal) { + throw new IllegalArgumentException(propertyName + + " must be static and non-final"); + } + modifyFieldIfSet(field, propertyName); + } + } + } else { + Log.w("android.os.Debug", + "setPropertiesOn(" + (cl == null ? "null" : cl.getName()) + + ") called in non-DEBUG build"); + } + } } |
