• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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