1 /* 2 * Copyright (C) 2024 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 17 package android.os.profiling; 18 19 import static android.os.profiling.ProfilingService.TracingState; 20 21 import android.annotation.NonNull; 22 import android.annotation.Nullable; 23 import android.os.Bundle; 24 import android.os.QueuedResultsWrapper; 25 import android.util.Log; 26 27 import java.util.UUID; 28 29 /** 30 * Represents a single in progress tracing session and all necessary data to manage and process it. 31 */ 32 public final class TracingSession { 33 private static final String TAG = TracingSession.class.getSimpleName(); 34 35 // LINT.IfChange(persisted_params) 36 // Persisted params 37 private final int mProfilingType; 38 private final int mTriggerType; 39 private final int mUid; 40 @NonNull private final String mPackageName; 41 @Nullable private final String mTag; 42 private final long mKeyMostSigBits; 43 private final long mKeyLeastSigBits; 44 @Nullable private String mFileName = null; 45 @Nullable private String mRedactedFileName = null; 46 @NonNull private TracingState mState; 47 private int mRetryCount = 0; 48 @Nullable private String mErrorMessage = null; 49 // Expected to be populated with ProfilingResult.ERROR_* values. 50 private int mErrorStatus = -1; // Default to invalid value. 51 private long mProfilingStartTimeMs; 52 // LINT.ThenChange(:from_proto) 53 54 // Non-persisted params 55 @Nullable private final Bundle mParams; 56 @Nullable private Process mActiveTrace; 57 @Nullable private Process mActiveRedaction; 58 @Nullable private Runnable mProcessResultRunnable; 59 @Nullable private String mKey = null; 60 @Nullable private String mDestinationFileName = null; 61 private long mRedactionStartTimeMs; 62 private int mMaxProfilingTimeAllowedMs = 0; 63 TracingSession(int profilingType, int uid, String packageName, int triggerType)64 public TracingSession(int profilingType, int uid, String packageName, int triggerType) { 65 this( 66 profilingType, 67 null, 68 uid, 69 packageName, 70 null, 71 0L, 72 0L, 73 triggerType); 74 } 75 TracingSession(int profilingType, Bundle params, int uid, String packageName, String tag, long keyMostSigBits, long keyLeastSigBits, int triggerType)76 public TracingSession(int profilingType, Bundle params, int uid, String packageName, String tag, 77 long keyMostSigBits, long keyLeastSigBits, int triggerType) { 78 mProfilingType = profilingType; 79 mTriggerType = triggerType; 80 mParams = params; 81 mUid = uid; 82 mPackageName = packageName; 83 mTag = tag; 84 mKeyMostSigBits = keyMostSigBits; 85 mKeyLeastSigBits = keyLeastSigBits; 86 mState = TracingState.REQUESTED; 87 } 88 89 // LINT.IfChange(from_proto) TracingSession(QueuedResultsWrapper.TracingSession sessionProto)90 public TracingSession(QueuedResultsWrapper.TracingSession sessionProto) { 91 mProfilingType = sessionProto.getProfilingType(); 92 mUid = sessionProto.getUid(); 93 mPackageName = sessionProto.getPackageName(); 94 mTag = sessionProto.getTag(); 95 mKeyMostSigBits = sessionProto.getKeyMostSigBits(); 96 mKeyLeastSigBits = sessionProto.getKeyLeastSigBits(); 97 if (sessionProto.hasFileName()) { 98 mFileName = sessionProto.getFileName(); 99 } 100 if (sessionProto.hasRedactedFileName()) { 101 mRedactedFileName = sessionProto.getRedactedFileName(); 102 } 103 mState = TracingState.of(sessionProto.getTracingState()); 104 mRetryCount = sessionProto.getRetryCount(); 105 if (sessionProto.hasErrorMessage()) { 106 mErrorMessage = sessionProto.getErrorMessage(); 107 } 108 mErrorStatus = sessionProto.getErrorStatus(); 109 mTriggerType = sessionProto.getTriggerType(); 110 mProfilingStartTimeMs = sessionProto.getProfilingStartTime(); 111 112 // params is not persisted because we cannot guarantee that it does not contain some large 113 // store of data, and because we don't need it anymore once the request has gotten to the 114 // point of being persisted. 115 mParams = null; 116 117 if (mState == null || mState.getValue() < TracingState.PROFILING_FINISHED.getValue()) { 118 // This should never happen. If state is null, then we can't know what to do next. If 119 // the state is earlier than PROFILING_FINISHED then it should not have been in the 120 // queue and therefore should not have been persisted. Either way, update the state to 121 // indicate that the caller was already notified (because we can't know what to notify), 122 // this will ensure that all that's remaining is cleanup. 123 mState = TracingState.NOTIFIED_REQUESTER; 124 Log.e(TAG, "Attempting to load a queued session with an invalid state."); 125 } 126 } 127 // LINT.ThenChange(:to_proto) 128 129 /** Generates the config for this request and converts to bytes. */ getConfigBytes()130 public byte[] getConfigBytes() throws IllegalArgumentException { 131 return Configs.generateConfigForRequest(mProfilingType, mParams, mPackageName); 132 } 133 134 /** 135 * Gets the amount of time before the system should start checking whether the profiling is 136 * complete so that post processing can begin. 137 */ getPostProcessingScheduleDelayMs()138 public int getPostProcessingScheduleDelayMs() throws IllegalArgumentException { 139 return Configs.getInitialProfilingTimeMs(mProfilingType, mParams); 140 } 141 142 /** 143 * Gets the maximum profiling time allowed for this TracingSession. 144 * @return maximum profiling time allowed in ms. 145 */ getMaxProfilingTimeAllowedMs()146 public int getMaxProfilingTimeAllowedMs() { 147 if (mMaxProfilingTimeAllowedMs != 0) { 148 return mMaxProfilingTimeAllowedMs; 149 } 150 mMaxProfilingTimeAllowedMs = 151 Configs.getMaxProfilingTimeAllowedMs(mProfilingType, mParams); 152 return mMaxProfilingTimeAllowedMs; 153 } 154 155 /** Get the tracing session unique key which was provided by {@link ProfilingManager}. */ 156 @Nullable getKey()157 public String getKey() { 158 if (mKey == null) { 159 mKey = (new UUID(mKeyMostSigBits, mKeyLeastSigBits)).toString(); 160 } 161 return mKey; 162 } 163 setActiveTrace(Process activeTrace)164 public void setActiveTrace(Process activeTrace) { 165 mActiveTrace = activeTrace; 166 } 167 setActiveRedaction(Process activeRedaction)168 public void setActiveRedaction(Process activeRedaction) { 169 mActiveRedaction = activeRedaction; 170 } 171 setProcessResultRunnable(Runnable processResultRunnable)172 public void setProcessResultRunnable(Runnable processResultRunnable) { 173 mProcessResultRunnable = processResultRunnable; 174 } 175 176 // The file set here will be the name of the file that perfetto creates regardless of the 177 // type of profiling that is being done. setFileName(String fileName)178 public void setFileName(String fileName) { 179 mFileName = fileName; 180 } 181 setRedactedFileName(String fileName)182 public void setRedactedFileName(String fileName) { 183 mRedactedFileName = fileName; 184 } 185 setRedactionStartTimeMs(long startTime)186 public void setRedactionStartTimeMs(long startTime) { 187 mRedactionStartTimeMs = startTime; 188 } 189 setRetryCount(int retryCount)190 public void setRetryCount(int retryCount) { 191 mRetryCount = retryCount; 192 } 193 194 /** 195 * Do not call directly! 196 * State should only be updated with {@link ProfilingService#advanceStateAndContinue}. 197 */ setState(TracingState state)198 public void setState(TracingState state) { 199 mState = state; 200 } 201 202 /** Increase retry count by 1 */ incrementRetryCount()203 public void incrementRetryCount() { 204 mRetryCount += 1; 205 } 206 setProfilingStartTimeMs(long startTime)207 public void setProfilingStartTimeMs(long startTime) { 208 mProfilingStartTimeMs = startTime; 209 } 210 211 /** 212 * Update error status. Also overrides error message to null as the two fields must be set 213 * together to ensure they make sense. 214 */ setError(int status)215 public void setError(int status) { 216 setError(status, null); 217 } 218 219 /** Update error status and message. */ setError(int status, String message)220 public void setError(int status, String message) { 221 mErrorStatus = status; 222 mErrorMessage = message; 223 } 224 225 @Nullable getActiveTrace()226 public Process getActiveTrace() { 227 return mActiveTrace; 228 } 229 230 @Nullable getActiveRedaction()231 public Process getActiveRedaction() { 232 return mActiveRedaction; 233 } 234 235 @Nullable getProcessResultRunnable()236 public Runnable getProcessResultRunnable() { 237 return mProcessResultRunnable; 238 } 239 getProfilingType()240 public int getProfilingType() { 241 return mProfilingType; 242 } 243 getUid()244 public int getUid() { 245 return mUid; 246 } 247 248 @NonNull getPackageName()249 public String getPackageName() { 250 return mPackageName; 251 } 252 253 @Nullable getTag()254 public String getTag() { 255 return mTag; 256 } 257 getKeyMostSigBits()258 public long getKeyMostSigBits() { 259 return mKeyMostSigBits; 260 } 261 getKeyLeastSigBits()262 public long getKeyLeastSigBits() { 263 return mKeyLeastSigBits; 264 } 265 266 // This returns the name of the file that perfetto created during profiling. If the profiling 267 // type was a trace collection it will return the unredacted trace file name. 268 @Nullable getFileName()269 public String getFileName() { 270 return mFileName; 271 } 272 273 @Nullable getRedactedFileName()274 public String getRedactedFileName() { 275 return mRedactedFileName; 276 } 277 getRedactionStartTimeMs()278 public long getRedactionStartTimeMs() { 279 return mRedactionStartTimeMs; 280 } 281 getProfilingStartTimeMs()282 public long getProfilingStartTimeMs() { 283 return mProfilingStartTimeMs; 284 } 285 286 /** 287 * Returns the relative path starting from apps storage dir including name of the file being 288 * returned to the client. 289 * @param appRelativePath relative path to app storage. 290 * @return relative file path and name of file. 291 */ 292 @Nullable getDestinationFileName(String appRelativePath)293 public String getDestinationFileName(String appRelativePath) { 294 if (mFileName == null) { 295 return null; 296 } 297 if (mDestinationFileName == null) { 298 mDestinationFileName = appRelativePath 299 + ((this.getRedactedFileName() == null) ? mFileName : mRedactedFileName); 300 } 301 return mDestinationFileName; 302 } 303 304 @NonNull getState()305 public TracingState getState() { 306 return mState; 307 } 308 getRetryCount()309 public int getRetryCount() { 310 return mRetryCount; 311 } 312 313 @Nullable getErrorMessage()314 public String getErrorMessage() { 315 return mErrorMessage; 316 } 317 getErrorStatus()318 public int getErrorStatus() { 319 return mErrorStatus; 320 } 321 getTriggerType()322 public int getTriggerType() { 323 return mTriggerType; 324 } 325 326 // LINT.IfChange(to_proto) 327 /** Convert this session to a proto for persisting. */ toProto()328 public QueuedResultsWrapper.TracingSession toProto() { 329 QueuedResultsWrapper.TracingSession.Builder tracingSessionBuilder = 330 QueuedResultsWrapper.TracingSession.newBuilder(); 331 332 tracingSessionBuilder.setProfilingType(mProfilingType); 333 tracingSessionBuilder.setUid(mUid); 334 tracingSessionBuilder.setPackageName(mPackageName); 335 if (mTag != null) { 336 tracingSessionBuilder.setTag(mTag); 337 } 338 tracingSessionBuilder.setKeyMostSigBits(mKeyMostSigBits); 339 tracingSessionBuilder.setKeyLeastSigBits(mKeyLeastSigBits); 340 if (mFileName != null) { 341 tracingSessionBuilder.setFileName(mFileName); 342 } 343 if (mRedactedFileName != null) { 344 tracingSessionBuilder.setRedactedFileName(mRedactedFileName); 345 } 346 tracingSessionBuilder.setTracingState(mState.getValue()); 347 tracingSessionBuilder.setRetryCount(mRetryCount); 348 if (mErrorMessage != null) { 349 tracingSessionBuilder.setErrorMessage(mErrorMessage); 350 } 351 tracingSessionBuilder.setErrorStatus(mErrorStatus); 352 tracingSessionBuilder.setTriggerType(mTriggerType); 353 tracingSessionBuilder.setProfilingStartTime(mProfilingStartTimeMs); 354 355 return tracingSessionBuilder.build(); 356 } 357 // LINT.ThenChange(/tests/cts/src/android/profiling/cts/ProfilingServiceTests.java:equals) 358 } 359