blob: bb04374971f93500afe7a5e6d61f2a5daec21c30 [file] [log] [blame]
Brad Ebinger116b8592015-11-18 11:40:11 -08001/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License
15 */
16
17package com.android.server.telecom;
18
19import android.annotation.NonNull;
20
21import java.util.ArrayList;
22
23/**
24 * The session that stores information about a thread's point of entry into the Telecom code that
25 * persists until the thread exits Telecom.
26 */
27public class Session {
28
29 public static final String START_SESSION = "START_SESSION";
30 public static final String CREATE_SUBSESSION = "CREATE_SUBSESSION";
31 public static final String CONTINUE_SUBSESSION = "CONTINUE_SUBSESSION";
32 public static final String END_SUBSESSION = "END_SUBSESSION";
33 public static final String END_SESSION = "END_SESSION";
34
35 public static final int UNDEFINED = -1;
36
37 private String mSessionId;
38 private String mShortMethodName;
39 private long mExecutionStartTimeMs;
40 private long mExecutionEndTimeMs = UNDEFINED;
41 private Session mParentSession;
42 private ArrayList<Session> mChildSessions;
43 private boolean mIsCompleted = false;
Brad Ebinger11623a32015-11-25 13:52:02 -080044 private int mChildCounter = 0;
45 private long mThreadId = 0;
Brad Ebinger209e4132015-12-17 15:10:14 -080046 // True if this is a subsession that has been started from the same thread as the parent
47 // session. This can happen if Log.startSession(...) is called multiple times on the same
48 // thread in the case of one Telecom entry point method calling another entry point method.
49 // In this case, we can just make this subsession "invisible," but still keep track of it so
50 // that the Log.endSession() calls match up.
Brad Ebinger69fbbf22015-12-16 10:44:10 -080051 private boolean mIsStartedFromActiveSession = false;
Brad Ebinger209e4132015-12-17 15:10:14 -080052 // Optionally provided info about the method/class/component that started the session in order
53 // to make Logging easier. This info will be provided in parentheses along with the session.
54 private String mOwnerInfo;
Brad Ebinger116b8592015-11-18 11:40:11 -080055
Brad Ebinger69fbbf22015-12-16 10:44:10 -080056 public Session(String sessionId, String shortMethodName, long startTimeMs, long threadID,
Brad Ebinger209e4132015-12-17 15:10:14 -080057 boolean isStartedFromActiveSession, String ownerInfo) {
Brad Ebinger116b8592015-11-18 11:40:11 -080058 setSessionId(sessionId);
59 setShortMethodName(shortMethodName);
60 mExecutionStartTimeMs = startTimeMs;
61 mParentSession = null;
62 mChildSessions = new ArrayList<>(5);
Brad Ebinger11623a32015-11-25 13:52:02 -080063 mThreadId = threadID;
Brad Ebinger69fbbf22015-12-16 10:44:10 -080064 mIsStartedFromActiveSession = isStartedFromActiveSession;
Brad Ebinger209e4132015-12-17 15:10:14 -080065 mOwnerInfo = ownerInfo;
Brad Ebinger116b8592015-11-18 11:40:11 -080066 }
67
68 public void setSessionId(@NonNull String sessionId) {
69 if(sessionId == null) {
70 mSessionId = "?";
71 }
72 mSessionId = sessionId;
73 }
74
75 public String getShortMethodName() {
76 return mShortMethodName;
77 }
78
79 public void setShortMethodName(String shortMethodName) {
80 if(shortMethodName == null) {
81 shortMethodName = "";
82 }
83 mShortMethodName = shortMethodName;
84 }
85
86 public void setParentSession(Session parentSession) {
87 mParentSession = parentSession;
88 }
89
90 public void addChild(Session childSession) {
91 if(childSession != null) {
92 mChildSessions.add(childSession);
93 }
94 }
95
96 public void removeChild(Session child) {
97 if(child != null) {
98 mChildSessions.remove(child);
99 }
100 }
101
102 public long getExecutionStartTimeMilliseconds() {
103 return mExecutionStartTimeMs;
104 }
105
Brad Ebinger11623a32015-11-25 13:52:02 -0800106 public void setExecutionStartTimeMs(long startTimeMs) {
107 mExecutionStartTimeMs = startTimeMs;
108 }
109
Brad Ebinger116b8592015-11-18 11:40:11 -0800110 public Session getParentSession() {
111 return mParentSession;
112 }
113
114 public ArrayList<Session> getChildSessions() {
115 return mChildSessions;
116 }
117
118 public boolean isSessionCompleted() {
119 return mIsCompleted;
120 }
121
Brad Ebinger69fbbf22015-12-16 10:44:10 -0800122 public boolean isStartedFromActiveSession() {
123 return mIsStartedFromActiveSession;
124 }
125
Brad Ebinger116b8592015-11-18 11:40:11 -0800126 // Mark this session complete. This will be deleted by Log when all subsessions are complete
127 // as well.
128 public void markSessionCompleted(long executionEndTimeMs) {
129 mExecutionEndTimeMs = executionEndTimeMs;
130 mIsCompleted = true;
131 }
132
133 public long getLocalExecutionTime() {
134 if(mExecutionEndTimeMs == UNDEFINED) {
135 return UNDEFINED;
136 }
137 return mExecutionEndTimeMs - mExecutionStartTimeMs;
138 }
139
Brad Ebinger11623a32015-11-25 13:52:02 -0800140 public synchronized String getNextChildId() {
141 return String.valueOf(mChildCounter++);
142 }
143
144 public long getThreadId () {
145 return mThreadId;
Brad Ebinger116b8592015-11-18 11:40:11 -0800146 }
147
148 @Override
149 public boolean equals(Object obj) {
150 if (!(obj instanceof Session)) {
151 return false;
152 }
153 if (obj == this) {
154 return true;
155 }
156 Session otherSession = (Session) obj;
157 return (mSessionId.equals(otherSession.mSessionId)) &&
158 (mShortMethodName.equals(otherSession.mShortMethodName)) &&
159 mExecutionStartTimeMs == otherSession.mExecutionStartTimeMs &&
160 mParentSession == otherSession.mParentSession &&
161 mChildSessions.equals(otherSession.mChildSessions) &&
162 mIsCompleted == otherSession.mIsCompleted &&
Brad Ebinger11623a32015-11-25 13:52:02 -0800163 mExecutionEndTimeMs == otherSession.mExecutionEndTimeMs &&
164 mChildCounter == otherSession.mChildCounter &&
Brad Ebinger69fbbf22015-12-16 10:44:10 -0800165 mThreadId == otherSession.mThreadId &&
Brad Ebinger209e4132015-12-17 15:10:14 -0800166 mIsStartedFromActiveSession == otherSession.mIsStartedFromActiveSession &&
167 mOwnerInfo == otherSession.mOwnerInfo;
Brad Ebinger116b8592015-11-18 11:40:11 -0800168 }
169
170 // Builds full session id recursively
171 private String getFullSessionId() {
172 if(mParentSession == null) {
173 return mSessionId;
174 } else {
175 return mParentSession.getFullSessionId() + "_" + mSessionId;
176 }
177 }
178
Brad Ebinger11623a32015-11-25 13:52:02 -0800179 // Print out the full Session tree from any subsession node
180 public String printFullSessionTree() {
181 // Get to the top of the tree
182 Session topNode = this;
183 while(topNode.getParentSession() != null) {
184 topNode = topNode.getParentSession();
185 }
186 return topNode.printSessionTree();
187 }
188
189 // Recursively move down session tree using DFS, but print out each node when it is reached.
190 public String printSessionTree() {
191 StringBuilder sb = new StringBuilder();
192 printSessionTree(0, sb);
193 return sb.toString();
194 }
195
196 private void printSessionTree(int tabI, StringBuilder sb) {
197 sb.append(toString());
198 for (Session child : mChildSessions) {
199 sb.append("\n");
200 for(int i = 0; i <= tabI; i++) {
201 sb.append("\t");
202 }
203 child.printSessionTree(tabI + 1, sb);
204 }
205 }
206
Brad Ebinger116b8592015-11-18 11:40:11 -0800207 @Override
208 public String toString() {
Brad Ebinger69fbbf22015-12-16 10:44:10 -0800209 if(mParentSession != null && mIsStartedFromActiveSession) {
210 // Log.startSession was called from within another active session. Use the parent's
211 // Id instead of the child to reduce confusion.
212 return mParentSession.toString();
213 } else {
Brad Ebinger209e4132015-12-17 15:10:14 -0800214 StringBuilder methodName = new StringBuilder();
215 methodName.append(mShortMethodName);
216 if(mOwnerInfo != null && !mOwnerInfo.isEmpty()) {
217 methodName.append("(InCall package: ");
218 methodName.append(mOwnerInfo);
219 methodName.append(")");
220 }
221 return methodName.toString() + "@" + getFullSessionId();
Brad Ebinger69fbbf22015-12-16 10:44:10 -0800222 }
Brad Ebinger116b8592015-11-18 11:40:11 -0800223 }
224}