From a51a9564fd53b661446cd63eea23208656acc678 Mon Sep 17 00:00:00 2001 From: Craig Mautner Date: Tue, 17 Apr 2012 17:05:26 -0700 Subject: [PATCH] Add call-stack reporting methods into Debug Added two public methods to Debug. These methods return a String indicating the caller (getCaller()) or callers (getCallers(int depth)) of the calling method. The String indicates the class, method and line number of the caller(s). Similar to using Throwable.fillInStackTrace() but much more concise. Change-Id: I53d0085aa50e4501d28e8eb3ad5b91ef700ac218 --- core/java/android/os/Debug.java | 38 +++++++++++ .../com/android/internal/os/DebugTest.java | 67 +++++++++++++++++++ .../server/wm/WindowManagerService.java | 25 +------ .../server/wm/WindowStateAnimator.java | 21 +++--- 4 files changed, 117 insertions(+), 34 deletions(-) create mode 100644 core/tests/coretests/src/com/android/internal/os/DebugTest.java diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java index 20a731e068dba..98fe06a20a68c 100644 --- a/core/java/android/os/Debug.java +++ b/core/java/android/os/Debug.java @@ -1324,4 +1324,42 @@ href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Lo return false; } } + + /** + * Return a String describing the calling method and location at a particular stack depth. + * @param callStack the Thread stack + * @param depth the depth of stack to return information for. + * @return the String describing the caller at that depth. + */ + private static String getCaller(StackTraceElement callStack[], int depth) { + // callStack[4] is the caller of the method that called getCallers() + if (4 + depth >= callStack.length) { + return ""; + } + StackTraceElement caller = callStack[4 + depth]; + return caller.getClassName() + "." + caller.getMethodName() + ":" + caller.getLineNumber(); + } + + /** + * Return a string consisting of methods and locations at multiple call stack levels. + * @param depth the number of levels to return, starting with the immediate caller. + * @return a string describing the call stack. + * {@hide} + */ + public static String getCallers(final int depth) { + final StackTraceElement[] callStack = Thread.currentThread().getStackTrace(); + StringBuffer sb = new StringBuffer(); + for (int i = 0; i < depth; i++) { + sb.append(getCaller(callStack, i)).append(" "); + } + return sb.toString(); + } + + /** + * @return a String describing the immediate caller of the calling function. + * {@hide} + */ + public static String getCaller() { + return getCaller(Thread.currentThread().getStackTrace(), 0); + } } diff --git a/core/tests/coretests/src/com/android/internal/os/DebugTest.java b/core/tests/coretests/src/com/android/internal/os/DebugTest.java new file mode 100644 index 0000000000000..88c7d1b18a6a8 --- /dev/null +++ b/core/tests/coretests/src/com/android/internal/os/DebugTest.java @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2012 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.internal.os; + +import android.os.Debug; + +import android.test.suitebuilder.annotation.SmallTest; +import junit.framework.TestCase; + +@SmallTest +public class DebugTest extends TestCase { + + private final static String EXPECTED_GET_CALLER = + "com\\.android\\.internal\\.os\\.DebugTest\\.testGetCaller:\\d\\d"; + private final static String EXPECTED_GET_CALLERS = + "com\\.android\\.internal\\.os\\.DebugTest.callDepth3:\\d\\d " + + "com\\.android\\.internal\\.os\\.DebugTest.callDepth2:\\d\\d " + + "com\\.android\\.internal\\.os\\.DebugTest.callDepth1:\\d\\d "; + + /** + * @return String consisting of the caller to this method. + */ + private String callDepth0() { + return Debug.getCaller(); + } + + public void testGetCaller() { + assertTrue(callDepth0().matches(EXPECTED_GET_CALLER)); + } + + /** + * @return String consisting of the callers to this method. + */ + private String callDepth4() { + return Debug.getCallers(3); + } + + private String callDepth3() { + return callDepth4(); + } + + private String callDepth2() { + return callDepth3(); + } + + private String callDepth1() { + return callDepth2(); + } + + public void testGetCallers() { + assertTrue(callDepth1().matches(EXPECTED_GET_CALLERS)); + } +} diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java index 72aab7b62feb3..966f4c147dfe4 100644 --- a/services/java/com/android/server/wm/WindowManagerService.java +++ b/services/java/com/android/server/wm/WindowManagerService.java @@ -8129,7 +8129,7 @@ public class WindowManagerService extends IWindowManager.Stub boolean recoveringMemory) { if (DEBUG_WINDOW_TRACE) { Slog.v(TAG, "performLayoutAndPlaceSurfacesLockedInner: entry. Called by " - + getCallers(3)); + + Debug.getCallers(3)); } if (mDisplay == null) { Slog.i(TAG, "skipping performLayoutAndPlaceSurfacesLockedInner with no mDisplay"); @@ -9621,27 +9621,4 @@ public class WindowManagerService extends IWindowManager.Stub mH.sendMessage(mH.obtainMessage(H.BULK_UPDATE_PARAMETERS, bulkUpdateParams, pendingLayoutChanges)); } - - /** - * Never call directly. Only call through getCallers(int) or getCaller(). Otherwise - * the depth will be off. - * @param depth What level stack to return. - * @return A String indicating who the caller of the method that calls this is. - */ - static String getCaller(int depth) { - StackTraceElement caller = Thread.currentThread().getStackTrace()[5 + depth]; - return caller.getClassName() + "." + caller.getMethodName() + ":" + caller.getLineNumber(); - } - - static String getCallers(final int depth) { - StringBuffer sb = new StringBuffer(); - for (int i = 0; i < depth; i++) { - sb.append(getCaller(i)).append(" "); - } - return sb.toString(); - } - - static String getCaller() { - return getCallers(1); - } } diff --git a/services/java/com/android/server/wm/WindowStateAnimator.java b/services/java/com/android/server/wm/WindowStateAnimator.java index b61ccbfabf404..0a7e7fd5a0f7c 100644 --- a/services/java/com/android/server/wm/WindowStateAnimator.java +++ b/services/java/com/android/server/wm/WindowStateAnimator.java @@ -15,6 +15,7 @@ import android.graphics.Point; import android.graphics.PointF; import android.graphics.Rect; import android.graphics.Region; +import android.os.Debug; import android.os.RemoteException; import android.util.Slog; import android.view.Surface; @@ -421,7 +422,7 @@ class WindowStateAnimator { super(s, pid, display, w, h, format, flags); mSize = new Point(w, h); Slog.v(SURFACE_TAG, "ctor: " + this + ". Called by " - + WindowManagerService.getCallers(3)); + + Debug.getCallers(3)); } public SurfaceTrace(SurfaceSession s, @@ -431,7 +432,7 @@ class WindowStateAnimator { mName = name; mSize = new Point(w, h); Slog.v(SURFACE_TAG, "ctor: " + this + ". Called by " - + WindowManagerService.getCallers(3)); + + Debug.getCallers(3)); } @Override @@ -439,7 +440,7 @@ class WindowStateAnimator { super.setAlpha(alpha); mSurfaceTraceAlpha = alpha; Slog.v(SURFACE_TAG, "setAlpha: " + this + ". Called by " - + WindowManagerService.getCallers(3)); + + Debug.getCallers(3)); } @Override @@ -447,7 +448,7 @@ class WindowStateAnimator { super.setLayer(zorder); mLayer = zorder; Slog.v(SURFACE_TAG, "setLayer: " + this + ". Called by " - + WindowManagerService.getCallers(3)); + + Debug.getCallers(3)); sSurfaces.remove(this); int i; @@ -465,7 +466,7 @@ class WindowStateAnimator { super.setPosition(x, y); mPosition = new PointF(x, y); Slog.v(SURFACE_TAG, "setPosition: " + this + ". Called by " - + WindowManagerService.getCallers(3)); + + Debug.getCallers(3)); } @Override @@ -473,7 +474,7 @@ class WindowStateAnimator { super.setSize(w, h); mSize = new Point(w, h); Slog.v(SURFACE_TAG, "setSize: " + this + ". Called by " - + WindowManagerService.getCallers(3)); + + Debug.getCallers(3)); } @Override @@ -481,21 +482,21 @@ class WindowStateAnimator { super.hide(); mShown = false; Slog.v(SURFACE_TAG, "hide: " + this + ". Called by " - + WindowManagerService.getCallers(3)); + + Debug.getCallers(3)); } @Override public void show() { super.show(); mShown = true; Slog.v(SURFACE_TAG, "show: " + this + ". Called by " - + WindowManagerService.getCallers(3)); + + Debug.getCallers(3)); } @Override public void destroy() { super.destroy(); Slog.v(SURFACE_TAG, "destroy: " + this + ". Called by " - + WindowManagerService.getCallers(3)); + + Debug.getCallers(3)); sSurfaces.remove(this); } @@ -503,7 +504,7 @@ class WindowStateAnimator { public void release() { super.release(); Slog.v(SURFACE_TAG, "release: " + this + ". Called by " - + WindowManagerService.getCallers(3)); + + Debug.getCallers(3)); sSurfaces.remove(this); }