Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a51a9564 authored by Craig Mautner's avatar Craig Mautner
Browse files

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
parent c843642f
Loading
Loading
Loading
Loading
+38 −0
Original line number Diff line number Diff line
@@ -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 "<bottom of call stack>";
        }
        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);
    }
}
+67 −0
Original line number Diff line number Diff line
/*
 * 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));
    }
}
+1 −24
Original line number Diff line number Diff line
@@ -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);
    }
}
+11 −10
Original line number Diff line number Diff line
@@ -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);
        }