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

Commit 1ac5238f authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Prevent Infinite Recursion in Telecom Sessions" into qt-qpr1-dev

parents c28d6232 13f23a85
Loading
Loading
Loading
Loading
+51 −19
Original line number Diff line number Diff line
@@ -33,6 +33,8 @@ import java.util.ArrayList;
 */
public class Session {

    public static final String LOG_TAG = "Session";

    public static final String START_SESSION = "START_SESSION";
    public static final String START_EXTERNAL_SESSION = "START_EXTERNAL_SESSION";
    public static final String CREATE_SUBSESSION = "CREATE_SUBSESSION";
@@ -45,6 +47,9 @@ public class Session {
    public static final String EXTERNAL_INDICATOR = "E-";
    public static final String TRUNCATE_STRING = "...";

    // Prevent infinite recursion by setting a reasonable limit.
    private static final int SESSION_RECURSION_LIMIT = 25;

    /**
     * Initial value of mExecutionEndTimeMs and the final value of {@link #getLocalExecutionTime()}
     * if the Session is canceled.
@@ -226,6 +231,15 @@ public class Session {

    // Builds full session id recursively
    private String getFullSessionId() {
        return getFullSessionId(0);
    }

    // keep track of calls and bail if we hit the recursion limit
    private String getFullSessionId(int parentCount) {
        if (parentCount >= SESSION_RECURSION_LIMIT) {
            Log.w(LOG_TAG, "getFullSessionId: Hit recursion limit!");
            return TRUNCATE_STRING + mSessionId;
        }
        // Cache mParentSession locally to prevent a concurrency problem where
        // Log.endParentSessions() is called while a logging statement is running (Log.i, for
        // example) and setting mParentSession to null in a different thread after the null check
@@ -235,42 +249,57 @@ public class Session {
            return mSessionId;
        } else {
            if (Log.VERBOSE) {
                return parentSession.getFullSessionId() +
                return parentSession.getFullSessionId(parentCount + 1)
                        // Append "_X" to subsession to show subsession designation.
                        SESSION_SEPARATION_CHAR_CHILD + mSessionId;
                        + SESSION_SEPARATION_CHAR_CHILD + mSessionId;
            } else {
                // Only worry about the base ID at the top of the tree.
                return parentSession.getFullSessionId();
                return parentSession.getFullSessionId(parentCount + 1);
            }

        }
    }

    // Print out the full Session tree from any subsession node
    public String printFullSessionTree() {
        // Get to the top of the tree
    private Session getRootSession(String callingMethod) {
        int currParentCount = 0;
        Session topNode = this;
        while (topNode.getParentSession() != null) {
            if (currParentCount >= SESSION_RECURSION_LIMIT) {
                Log.w(LOG_TAG, "getRootSession: Hit recursion limit from " + callingMethod);
                break;
            }
            topNode = topNode.getParentSession();
            currParentCount++;
        }
        return topNode.printSessionTree();
        return topNode;
    }

    // Print out the full Session tree from any subsession node
    public String printFullSessionTree() {
        return getRootSession("printFullSessionTree").printSessionTree();
    }

    // Recursively move down session tree using DFS, but print out each node when it is reached.
    public String printSessionTree() {
    private String printSessionTree() {
        StringBuilder sb = new StringBuilder();
        printSessionTree(0, sb);
        printSessionTree(0, sb, 0);
        return sb.toString();
    }

    private void printSessionTree(int tabI, StringBuilder sb) {
    private void printSessionTree(int tabI, StringBuilder sb, int currChildCount) {
        // Prevent infinite recursion.
        if (currChildCount >= SESSION_RECURSION_LIMIT) {
            Log.w(LOG_TAG, "printSessionTree: Hit recursion limit!");
            sb.append(TRUNCATE_STRING);
            return;
        }
        sb.append(toString());
        for (Session child : mChildSessions) {
            sb.append("\n");
            for (int i = 0; i <= tabI; i++) {
                sb.append("\t");
            }
            child.printSessionTree(tabI + 1, sb);
            child.printSessionTree(tabI + 1, sb, currChildCount + 1);
        }
    }

@@ -279,11 +308,17 @@ public class Session {
    // recent) will be truncated to "..."
    public String getFullMethodPath(boolean truncatePath) {
        StringBuilder sb = new StringBuilder();
        getFullMethodPath(sb, truncatePath);
        getFullMethodPath(sb, truncatePath, 0);
        return sb.toString();
    }

    private synchronized void getFullMethodPath(StringBuilder sb, boolean truncatePath) {
    private synchronized void getFullMethodPath(StringBuilder sb, boolean truncatePath,
            int parentCount) {
        if (parentCount >= SESSION_RECURSION_LIMIT) {
            Log.w(LOG_TAG, "getFullMethodPath: Hit recursion limit!");
            sb.append(TRUNCATE_STRING);
            return;
        }
        // Return cached value for method path. When returning the truncated path, recalculate the
        // full path without using the cached value.
        if (!TextUtils.isEmpty(mFullMethodPathCache) && !truncatePath) {
@@ -296,7 +331,7 @@ public class Session {
            // Check to see if the session has been renamed yet. If it has not, then the session
            // has not been continued.
            isSessionStarted = !mShortMethodName.equals(parentSession.mShortMethodName);
            parentSession.getFullMethodPath(sb, truncatePath);
            parentSession.getFullMethodPath(sb, truncatePath, parentCount + 1);
            sb.append(SUBSESSION_SEPARATION_CHAR);
        }
        // Encapsulate the external session's method name so it is obvious what part of the session
@@ -319,13 +354,10 @@ public class Session {
            mFullMethodPathCache = sb.toString();
        }
    }

    // Recursively move to the top of the tree to see if the parent session is external.
    private boolean isSessionExternal() {
        if (getParentSession() == null) {
            return isExternal();
        } else {
            return getParentSession().isSessionExternal();
        }
        return getRootSession("isSessionExternal").isExternal();
    }

    @Override