1 /*
2  * Copyright 2023 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 androidx.tracing.perfetto.internal.handshake.protocol
18 
19 import androidx.annotation.IntDef
20 import androidx.annotation.RestrictTo
21 import androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP
22 
23 // Keep these two packages in sync:
24 // - `androidx.tracing.perfetto.handshake.protocol` in the tracing/tracing-perfetto-handshake folder
25 // - `androidx.tracing.perfetto.internal.handshake.protocol` in the tracing/tracing-perfetto folder
26 //
27 // This is a part of a WIP refactor to decouple tracing-perfetto and tracing-perfetto-handshake
28 // tracked under TODO(243405142)
29 
30 @RestrictTo(LIBRARY_GROUP)
31 internal object RequestKeys {
32     public const val RECEIVER_CLASS_NAME: String = "androidx.tracing.perfetto.TracingReceiver"
33 
34     /**
35      * Request to enable tracing in an app.
36      *
37      * The action is performed straight away allowing for warm / hot tracing. For cold start tracing
38      * see [ACTION_ENABLE_TRACING_COLD_START]
39      *
40      * Request can include [KEY_PATH] as an optional extra.
41      *
42      * Response to the request is a JSON string (to allow for CLI support) with the following:
43      * - [ResponseKeys.KEY_RESULT_CODE] (always)
44      * - [ResponseKeys.KEY_REQUIRED_VERSION] (always)
45      * - [ResponseKeys.KEY_MESSAGE] (optional)
46      */
47     public const val ACTION_ENABLE_TRACING: String =
48         "androidx.tracing.perfetto.action.ENABLE_TRACING"
49 
50     /**
51      * Request to enable cold start tracing in an app.
52      *
53      * For warm / hot tracing, see [ACTION_ENABLE_TRACING].
54      *
55      * The action must be performed in the following order, otherwise its effects are unspecified:
56      * - the app process must be killed before performing the action
57      * - the action must then follow
58      * - the app process must be killed after performing the action
59      *
60      * Request can include [KEY_PATH] as an optional extra. Request can include [KEY_PERSISTENT] as
61      * an optional extra.
62      *
63      * Response to the request is a JSON string (to allow for CLI support) with the following:
64      * - [ResponseKeys.KEY_RESULT_CODE] (always)
65      * - [ResponseKeys.KEY_REQUIRED_VERSION] (always)
66      * - [ResponseKeys.KEY_MESSAGE] (optional)
67      */
68     public const val ACTION_ENABLE_TRACING_COLD_START: String =
69         "androidx.tracing.perfetto.action.ENABLE_TRACING_COLD_START"
70 
71     /**
72      * Request to disable cold start tracing (previously enabled with
73      * [ACTION_ENABLE_TRACING_COLD_START]).
74      *
75      * The action is particularly useful when cold start tracing was enabled in [KEY_PERSISTENT]
76      * mode.
77      *
78      * The action must be performed in the following order, otherwise its effects are unspecified:
79      * - the app process must be killed before performing the action
80      * - the action must then follow
81      * - the app process must be killed after performing the action
82      *
83      * Request can include [KEY_PATH] as an optional extra. Request can include [KEY_PERSISTENT] as
84      * an optional extra.
85      *
86      * Response to the request is a JSON string (to allow for CLI support) with the following:
87      * - [ResponseKeys.KEY_RESULT_CODE] (always)
88      */
89     public const val ACTION_DISABLE_TRACING_COLD_START: String =
90         "androidx.tracing.perfetto.action.DISABLE_TRACING_COLD_START"
91 
92     /** Path to tracing native binary file */
93     public const val KEY_PATH: String = "path"
94 
95     /**
96      * Boolean flag to signify whether the operation should be persistent between runs (or only
97      * performed once).
98      *
99      * Applies to [ACTION_ENABLE_TRACING_COLD_START]
100      */
101     public const val KEY_PERSISTENT: String = "persistent"
102 }
103 
104 @RestrictTo(LIBRARY_GROUP)
105 internal object ResponseKeys {
106     /**
107      * Result code as listed in [ResponseResultCodes].
108      *
109      * Note: the value of the string ("exitCode") is kept unchanged to maintain backwards
110      * compatibility.
111      */
112     public const val KEY_RESULT_CODE: String = "exitCode"
113 
114     /**
115      * Required version of the binaries. Java and binary library versions have to match to ensure
116      * compatibility. In the Maven format, e.g. 1.2.3-beta01.
117      */
118     public const val KEY_REQUIRED_VERSION: String = "requiredVersion"
119 
120     /**
121      * Message string that gives more information about the response, e.g. recovery steps if
122      * applicable.
123      */
124     public const val KEY_MESSAGE: String = "message"
125 }
126 
127 internal object ResponseResultCodes {
128     /**
129      * Indicates that the broadcast resulted in `result=0`, which is an equivalent of
130      * [android.app.Activity.RESULT_CANCELED].
131      *
132      * This most likely means that the app does not expose a [PerfettoSdkHandshake] compatible
133      * receiver.
134      */
135     @Suppress("KDocUnresolvedReference") public const val RESULT_CODE_CANCELLED: Int = 0
136 
137     public const val RESULT_CODE_SUCCESS: Int = 1
138     public const val RESULT_CODE_ALREADY_ENABLED: Int = 2
139 
140     /**
141      * Required version described in [Response.requiredVersion]. A follow-up
142      * [androidx.tracing.perfetto.handshake.PerfettoSdkHandshake.enableTracingImmediate] request
143      * expected with binaries to sideload specified.
144      */
145     public const val RESULT_CODE_ERROR_BINARY_MISSING: Int = 11
146 
147     /** Required version described in [Response.requiredVersion]. */
148     public const val RESULT_CODE_ERROR_BINARY_VERSION_MISMATCH: Int = 12
149 
150     /**
151      * Could be a result of a stale version of the binary cached locally. Retrying with a freshly
152      * downloaded library likely to fix the issue. More specific information in [Response.message]
153      */
154     public const val RESULT_CODE_ERROR_BINARY_VERIFICATION_ERROR: Int = 13
155 
156     /** More specific information in [Response.message] */
157     public const val RESULT_CODE_ERROR_OTHER: Int = 99
158 }
159 
160 @Retention(AnnotationRetention.SOURCE)
161 @IntDef(
162     ResponseResultCodes.RESULT_CODE_CANCELLED,
163     ResponseResultCodes.RESULT_CODE_SUCCESS,
164     ResponseResultCodes.RESULT_CODE_ALREADY_ENABLED,
165     ResponseResultCodes.RESULT_CODE_ERROR_BINARY_MISSING,
166     ResponseResultCodes.RESULT_CODE_ERROR_BINARY_VERSION_MISMATCH,
167     ResponseResultCodes.RESULT_CODE_ERROR_BINARY_VERIFICATION_ERROR,
168     ResponseResultCodes.RESULT_CODE_ERROR_OTHER
169 )
170 private annotation class ResultCode
171 
172 internal class Response
173 @RestrictTo(LIBRARY_GROUP)
174 constructor(
175     @ResultCode public val resultCode: Int,
176 
177     /**
178      * This can be `null` iff we cannot communicate with the broadcast receiver of the target
179      * process (e.g. app does not offer Perfetto tracing) or if we cannot parse the response from
180      * the receiver. In either case, tracing is unlikely to work under these circumstances, and more
181      * context on how to proceed can be found in [resultCode] or [message] properties.
182      */
183     public val requiredVersion: String?,
184     public val message: String?
185 )
186