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
18 
19 import android.content.Context
20 import android.os.Build
21 import android.os.StrictMode
22 import android.util.Log
23 import androidx.startup.Initializer
24 import androidx.tracing.perfetto.internal.handshake.protocol.Response
25 import java.io.File
26 
27 /** Enables tracing at app startup if configured prior to app starting */
28 class StartupTracingInitializer : Initializer<Unit> {
29     private companion object {
30         private val TAG = StartupTracingInitializer::class.java.name
31     }
32 
createnull33     override fun create(context: Context) {
34         // TODO(234351579): Support API < 30
35         if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) return
36 
37         suppressStrictModeDiskWrites {
38             // read startup tracing config if present
39             val config =
40                 StartupTracingConfigStore.load(context)
41                     ?: return // early exit if no config is found
42 
43             // delete config if not meant to be preserved between runs
44             if (!config.isPersistent) StartupTracingConfigStore.clear(context)
45 
46             // enable tracing
47             val libFilePath = config.libFilePath
48             val enableTracingResponse =
49                 if (libFilePath == null) PerfettoSdkTrace.enable()
50                 else PerfettoSdkTrace.enable(File(libFilePath), context)
51 
52             // log the result for debuggability
53             Log.d(
54                 TAG,
55                 "${Response::class.java.name}: { " +
56                     "resultCode: ${enableTracingResponse.resultCode}, " +
57                     "message: ${enableTracingResponse.message}, " +
58                     "requiredVersion: ${enableTracingResponse.requiredVersion} " +
59                     "}"
60             )
61         }
62     }
63 
dependenciesnull64     override fun dependencies(): List<Class<out Initializer<*>>> = emptyList()
65 
66     // TODO(245426369): test in TrivialStartupTracingBenchmark
67     private inline fun <R> suppressStrictModeDiskWrites(block: () -> R): R {
68         val oldPolicy = StrictMode.allowThreadDiskWrites()
69         try {
70             return block()
71         } finally {
72             StrictMode.setThreadPolicy(oldPolicy)
73         }
74     }
75 }
76