1 /* 2 * Copyright (C) 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 android.os.profiling; 18 19 import android.annotation.Nullable; 20 import android.os.Bundle; 21 import android.os.ProfilingManager; 22 import android.provider.DeviceConfig; 23 24 import perfetto.protos.DataSourceConfigOuterClass.DataSourceConfig; 25 import perfetto.protos.FtraceConfigOuterClass.FtraceConfig; 26 import perfetto.protos.HeapprofdConfigOuterClass.HeapprofdConfig; 27 import perfetto.protos.JavaHprofConfigOuterClass.JavaHprofConfig; 28 import perfetto.protos.PackagesListConfigOuterClass.PackagesListConfig; 29 import perfetto.protos.PerfEventConfigOuterClass.PerfEventConfig; 30 import perfetto.protos.PerfEventsOuterClass.PerfEvents; 31 import perfetto.protos.ProcessStatsConfigOuterClass.ProcessStatsConfig; 32 import perfetto.protos.TraceConfigOuterClass.TraceConfig; 33 34 public final class Configs { 35 36 // Time to wait beyond trace timeout to ensure perfetto has time to finish writing output. 37 private static final int FILE_PROCESSING_DELAY_MS = 2000; 38 // Time used to account for any delay in starting up the underlying profiling process. This 39 // value is used to calculate max profiling time. 40 private static final int MAX_PROFILING_TIME_BUFFER_MS = 10 * 1000; 41 42 private static final int FOUR_MB = 4096; 43 44 private static final int ONE_DAY_MS = 24 * 60 * 60 * 1000; 45 46 private static boolean sSystemTriggeredSystemTraceConfigsInitialized = false; 47 private static boolean sSystemTraceConfigsInitialized = false; 48 private static boolean sHeapProfileConfigsInitialized = false; 49 private static boolean sJavaHeapDumpConfigsInitialized = false; 50 private static boolean sStackSamplingConfigsInitialized = false; 51 52 private static int sSystemTriggeredSystemTraceDurationMs; 53 private static int sSystemTriggeredSystemTraceDiscardBufferSizeKb; 54 private static int sSystemTriggeredSystemTraceRingBufferSizeKb; 55 56 private static boolean sKillswitchSystemTrace; 57 private static int sSystemTraceDurationMsDefault; 58 private static int sSystemTraceDurationMsMin; 59 private static int sSystemTraceDurationMsMax; 60 private static int sSystemTraceSizeKbDefault; 61 private static int sSystemTraceSizeKbMin; 62 private static int sSystemTraceSizeKbMax; 63 64 private static boolean sKillswitchHeapProfile; 65 private static boolean sHeapProfileTrackJavaAllocationsDefault; 66 private static int sHeapProfileFlushTimeoutMsDefault; 67 private static int sHeapProfileDurationMsDefault; 68 private static int sHeapProfileDurationMsMin; 69 private static int sHeapProfileDurationMsMax; 70 private static int sHeapProfileSizeKbDefault; 71 private static int sHeapProfileSizeKbMin; 72 private static int sHeapProfileSizeKbMax; 73 private static long sHeapProfileSamplingIntervalBytesDefault; 74 private static long sHeapProfileSamplingIntervalBytesMin; 75 private static long sHeapProfileSamplingIntervalBytesMax; 76 77 private static boolean sKillswitchJavaHeapDump; 78 private static int sJavaHeapDumpDurationMsDefault; 79 private static int sJavaHeapDumpDataSourceStopTimeoutMsDefault; 80 private static int sJavaHeapDumpSizeKbDefault; 81 private static int sJavaHeapDumpSizeKbMin; 82 private static int sJavaHeapDumpSizeKbMax; 83 84 private static boolean sKillswitchStackSampling; 85 private static int sStackSamplingFlushTimeoutMsDefault; 86 private static int sStackSamplingDurationMsDefault; 87 private static int sStackSamplingDurationMsMin; 88 private static int sStackSamplingDurationMsMax; 89 private static int sStackSamplingSizeKbDefault; 90 private static int sStackSamplingSizeKbMin; 91 private static int sStackSamplingSizeKbMax; 92 private static int sStackSamplingSamplingFrequencyDefault; 93 private static int sStackSamplingSamplingFrequencyMin; 94 private static int sStackSamplingSamplingFrequencyMax; 95 96 /** 97 * Initialize System Triggered System Trace related DeviceConfig values if they have not been 98 * yet. 99 */ initializeSystemTriggeredSystemTraceConfigsIfNecessary()100 private static void initializeSystemTriggeredSystemTraceConfigsIfNecessary() { 101 if (sSystemTriggeredSystemTraceConfigsInitialized) { 102 return; 103 } 104 105 DeviceConfig.Properties properties = 106 DeviceConfigHelper.getAllSystemTriggeredSystemTraceProperties(); 107 108 sSystemTriggeredSystemTraceDurationMs = properties.getInt( 109 DeviceConfigHelper.SYSTEM_TRIGGERED_SYSTEM_TRACE_DURATION_MS, 110 30 * 60 * 1000 /* 30 minutes */); 111 sSystemTriggeredSystemTraceDiscardBufferSizeKb = properties.getInt( 112 DeviceConfigHelper.SYSTEM_TRIGGERED_SYSTEM_TRACE_DISCARD_BUFFER_SIZE_KB, FOUR_MB); 113 sSystemTriggeredSystemTraceRingBufferSizeKb = properties.getInt( 114 DeviceConfigHelper.SYSTEM_TRIGGERED_SYSTEM_TRACE_RING_BUFFER_SIZE_KB, 32768); 115 116 sSystemTriggeredSystemTraceConfigsInitialized = true; 117 } 118 119 /** Initialize System Trace related DeviceConfig set values if they have not been yet. */ initializeSystemTraceConfigsIfNecessary()120 private static void initializeSystemTraceConfigsIfNecessary() { 121 if (sSystemTraceConfigsInitialized) { 122 return; 123 } 124 125 DeviceConfig.Properties properties = DeviceConfigHelper.getAllSystemTraceProperties(); 126 127 sKillswitchSystemTrace = properties.getBoolean( 128 DeviceConfigHelper.KILLSWITCH_SYSTEM_TRACE, false); 129 sSystemTraceDurationMsDefault = properties.getInt( 130 DeviceConfigHelper.SYSTEM_TRACE_DURATION_MS_DEFAULT, 300000); 131 sSystemTraceDurationMsMin = properties.getInt( 132 DeviceConfigHelper.SYSTEM_TRACE_DURATION_MS_MIN, 1000); 133 sSystemTraceDurationMsMax = properties.getInt( 134 DeviceConfigHelper.SYSTEM_TRACE_DURATION_MS_MAX, 600000); 135 sSystemTraceSizeKbDefault = properties.getInt( 136 DeviceConfigHelper.SYSTEM_TRACE_SIZE_KB_DEFAULT, 32768); 137 sSystemTraceSizeKbMin = properties.getInt( 138 DeviceConfigHelper.SYSTEM_TRACE_SIZE_KB_MIN, 64); 139 sSystemTraceSizeKbMax = properties.getInt( 140 DeviceConfigHelper.SYSTEM_TRACE_SIZE_KB_MAX, 32768); 141 142 sSystemTraceConfigsInitialized = true; 143 } 144 145 /** Initialize Java Heap Dump related DeviceConfig set values if they have not been yet. */ initializeJavaHeapDumpConfigsIfNecessary()146 private static void initializeJavaHeapDumpConfigsIfNecessary() { 147 if (sJavaHeapDumpConfigsInitialized) { 148 return; 149 } 150 151 DeviceConfig.Properties properties = DeviceConfigHelper.getAllJavaHeapDumpProperties(); 152 153 sKillswitchJavaHeapDump = properties.getBoolean( 154 DeviceConfigHelper.KILLSWITCH_JAVA_HEAP_DUMP, false); 155 sJavaHeapDumpDurationMsDefault = properties.getInt( 156 DeviceConfigHelper.JAVA_HEAP_DUMP_DURATION_MS_DEFAULT, 1000); 157 sJavaHeapDumpDataSourceStopTimeoutMsDefault = properties.getInt( 158 DeviceConfigHelper.JAVA_HEAP_DUMP_DATA_SOURCE_STOP_TIMEOUT_MS_DEFAULT, 100000); 159 sJavaHeapDumpSizeKbDefault = properties.getInt( 160 DeviceConfigHelper.JAVA_HEAP_DUMP_SIZE_KB_DEFAULT, 256000); 161 sJavaHeapDumpSizeKbMin = properties.getInt( 162 DeviceConfigHelper.JAVA_HEAP_DUMP_SIZE_KB_MIN, 8192 /* 8 MB */); 163 sJavaHeapDumpSizeKbMax = properties.getInt( 164 DeviceConfigHelper.JAVA_HEAP_DUMP_SIZE_KB_MAX, 256000); 165 166 sJavaHeapDumpConfigsInitialized = true; 167 } 168 169 /** Initialize Heap Profile related DeviceConfig set values if they have not been yet. */ initializeHeapProfileConfigsIfNecessary()170 private static void initializeHeapProfileConfigsIfNecessary() { 171 if (sHeapProfileConfigsInitialized) { 172 return; 173 } 174 175 DeviceConfig.Properties properties = DeviceConfigHelper.getAllHeapProfileProperties(); 176 177 sKillswitchHeapProfile = properties.getBoolean( 178 DeviceConfigHelper.KILLSWITCH_HEAP_PROFILE, false); 179 sHeapProfileTrackJavaAllocationsDefault = properties.getBoolean( 180 DeviceConfigHelper.HEAP_PROFILE_TRACK_JAVA_ALLOCATIONS_DEFAULT, false); 181 sHeapProfileFlushTimeoutMsDefault = properties.getInt( 182 DeviceConfigHelper.HEAP_PROFILE_FLUSH_TIMEOUT_MS_DEFAULT, 30000); 183 sHeapProfileDurationMsDefault = properties.getInt( 184 DeviceConfigHelper.HEAP_PROFILE_DURATION_MS_DEFAULT, 120000); 185 sHeapProfileDurationMsMin = properties.getInt( 186 DeviceConfigHelper.HEAP_PROFILE_DURATION_MS_MIN, 1000); 187 sHeapProfileDurationMsMax = properties.getInt( 188 DeviceConfigHelper.HEAP_PROFILE_DURATION_MS_MAX, 300000); 189 sHeapProfileSizeKbDefault = properties.getInt( 190 DeviceConfigHelper.HEAP_PROFILE_SIZE_KB_DEFAULT, 65536); 191 sHeapProfileSizeKbMin = properties.getInt( 192 DeviceConfigHelper.HEAP_PROFILE_SIZE_KB_MIN, 256); 193 sHeapProfileSizeKbMax = properties.getInt( 194 DeviceConfigHelper.HEAP_PROFILE_SIZE_KB_MAX, 65536); 195 sHeapProfileSamplingIntervalBytesDefault = properties.getLong( 196 DeviceConfigHelper.HEAP_PROFILE_SAMPLING_INTERVAL_BYTES_DEFAULT, 4096L); 197 sHeapProfileSamplingIntervalBytesMin = properties.getLong( 198 DeviceConfigHelper.HEAP_PROFILE_SAMPLING_INTERVAL_BYTES_MIN, 1L); 199 sHeapProfileSamplingIntervalBytesMax = properties.getLong( 200 DeviceConfigHelper.HEAP_PROFILE_SAMPLING_INTERVAL_BYTES_MAX, 65536L); 201 202 sHeapProfileConfigsInitialized = true; 203 } 204 205 /** Initialize Stack Sampling related DeviceConfig set values if they have not been yet. */ initializeStackSamplingConfigsIfNecessary()206 private static void initializeStackSamplingConfigsIfNecessary() { 207 if (sStackSamplingConfigsInitialized) { 208 return; 209 } 210 211 DeviceConfig.Properties properties = DeviceConfigHelper.getAllStackSamplingProperties(); 212 213 sKillswitchStackSampling = properties.getBoolean( 214 DeviceConfigHelper.KILLSWITCH_STACK_SAMPLING, false); 215 sStackSamplingFlushTimeoutMsDefault = properties.getInt( 216 DeviceConfigHelper.STACK_SAMPLING_FLUSH_TIMEOUT_MS_DEFAULT, 30000); 217 sStackSamplingDurationMsDefault = properties.getInt( 218 DeviceConfigHelper.STACK_SAMPLING_DURATION_MS_DEFAULT, 60000); 219 sStackSamplingDurationMsMin = properties.getInt( 220 DeviceConfigHelper.STACK_SAMPLING_DURATION_MS_MIN, 1000); 221 sStackSamplingDurationMsMax = properties.getInt( 222 DeviceConfigHelper.STACK_SAMPLING_DURATION_MS_MAX, 300000); 223 sStackSamplingSizeKbDefault = properties.getInt( 224 DeviceConfigHelper.STACK_SAMPLING_SAMPLING_SIZE_KB_DEFAULT, 65536); 225 sStackSamplingSizeKbMin = properties.getInt( 226 DeviceConfigHelper.STACK_SAMPLING_SAMPLING_SIZE_KB_MIN, 64); 227 sStackSamplingSizeKbMax = properties.getInt( 228 DeviceConfigHelper.STACK_SAMPLING_SAMPLING_SIZE_KB_MAX, 65536); 229 sStackSamplingSamplingFrequencyDefault = properties.getInt( 230 DeviceConfigHelper.STACK_SAMPLING_FREQUENCY_DEFAULT, 100); 231 sStackSamplingSamplingFrequencyMin = properties.getInt( 232 DeviceConfigHelper.STACK_SAMPLING_FREQUENCY_MIN, 1); 233 sStackSamplingSamplingFrequencyMax = properties.getInt( 234 DeviceConfigHelper.STACK_SAMPLING_FREQUENCY_MAX, 200); 235 236 sStackSamplingConfigsInitialized = true; 237 } 238 239 /** 240 * Update DeviceConfig set configuration values if present in the provided properties, leaving 241 * not present values unchanged. 242 * 243 * Will only update values that have already been initialized as initialization is required 244 * before use and the changed values will be available under the normal access path. 245 */ maybeUpdateConfigs(DeviceConfig.Properties properties)246 public static void maybeUpdateConfigs(DeviceConfig.Properties properties) { 247 // TODO(b/330940387): Revisit defaults before release 248 249 if (sSystemTraceConfigsInitialized) { 250 sKillswitchSystemTrace = properties.getBoolean( 251 DeviceConfigHelper.KILLSWITCH_SYSTEM_TRACE, sKillswitchSystemTrace); 252 sSystemTraceDurationMsDefault = properties.getInt( 253 DeviceConfigHelper.SYSTEM_TRACE_DURATION_MS_DEFAULT, 254 sSystemTraceDurationMsDefault); 255 sSystemTraceDurationMsMin = properties.getInt( 256 DeviceConfigHelper.SYSTEM_TRACE_DURATION_MS_MIN, sSystemTraceDurationMsMin); 257 sSystemTraceDurationMsMax = properties.getInt( 258 DeviceConfigHelper.SYSTEM_TRACE_DURATION_MS_MAX, sSystemTraceDurationMsMax); 259 sSystemTraceSizeKbDefault = properties.getInt( 260 DeviceConfigHelper.SYSTEM_TRACE_SIZE_KB_DEFAULT, sSystemTraceSizeKbDefault); 261 sSystemTraceSizeKbMin = properties.getInt( 262 DeviceConfigHelper.SYSTEM_TRACE_SIZE_KB_MIN, sSystemTraceSizeKbMin); 263 sSystemTraceSizeKbMax = properties.getInt( 264 DeviceConfigHelper.SYSTEM_TRACE_SIZE_KB_MAX, sSystemTraceSizeKbMax); 265 } 266 267 if (sHeapProfileConfigsInitialized) { 268 sKillswitchHeapProfile = properties.getBoolean( 269 DeviceConfigHelper.KILLSWITCH_HEAP_PROFILE, sKillswitchHeapProfile); 270 sHeapProfileTrackJavaAllocationsDefault = properties.getBoolean( 271 DeviceConfigHelper.HEAP_PROFILE_TRACK_JAVA_ALLOCATIONS_DEFAULT, 272 sHeapProfileTrackJavaAllocationsDefault); 273 sHeapProfileFlushTimeoutMsDefault = properties.getInt( 274 DeviceConfigHelper.HEAP_PROFILE_FLUSH_TIMEOUT_MS_DEFAULT, 275 sHeapProfileFlushTimeoutMsDefault); 276 sHeapProfileDurationMsDefault = properties.getInt( 277 DeviceConfigHelper.HEAP_PROFILE_DURATION_MS_DEFAULT, 278 sHeapProfileDurationMsDefault); 279 sHeapProfileDurationMsMin = properties.getInt( 280 DeviceConfigHelper.HEAP_PROFILE_DURATION_MS_MIN, sHeapProfileDurationMsMin); 281 sHeapProfileDurationMsMax = properties.getInt( 282 DeviceConfigHelper.HEAP_PROFILE_DURATION_MS_MAX, sHeapProfileDurationMsMax); 283 sHeapProfileSizeKbDefault = properties.getInt( 284 DeviceConfigHelper.HEAP_PROFILE_SIZE_KB_DEFAULT, sHeapProfileSizeKbDefault); 285 sHeapProfileSizeKbMin = properties.getInt( 286 DeviceConfigHelper.HEAP_PROFILE_SIZE_KB_MIN, sHeapProfileSizeKbMin); 287 sHeapProfileSizeKbMax = properties.getInt( 288 DeviceConfigHelper.HEAP_PROFILE_SIZE_KB_MAX, sHeapProfileSizeKbMax); 289 sHeapProfileSamplingIntervalBytesDefault = properties.getLong( 290 DeviceConfigHelper.HEAP_PROFILE_SAMPLING_INTERVAL_BYTES_DEFAULT, 291 sHeapProfileSamplingIntervalBytesDefault); 292 sHeapProfileSamplingIntervalBytesMin = properties.getLong( 293 DeviceConfigHelper.HEAP_PROFILE_SAMPLING_INTERVAL_BYTES_MIN, 294 sHeapProfileSamplingIntervalBytesMin); 295 sHeapProfileSamplingIntervalBytesMax = properties.getLong( 296 DeviceConfigHelper.HEAP_PROFILE_SAMPLING_INTERVAL_BYTES_MAX, 297 sHeapProfileSamplingIntervalBytesMax); 298 } 299 300 if (sJavaHeapDumpConfigsInitialized) { 301 sKillswitchJavaHeapDump = properties.getBoolean( 302 DeviceConfigHelper.KILLSWITCH_JAVA_HEAP_DUMP, sKillswitchJavaHeapDump); 303 sJavaHeapDumpDurationMsDefault = properties.getInt( 304 DeviceConfigHelper.JAVA_HEAP_DUMP_DURATION_MS_DEFAULT, 305 sJavaHeapDumpDurationMsDefault); 306 sJavaHeapDumpDataSourceStopTimeoutMsDefault = properties.getInt( 307 DeviceConfigHelper.JAVA_HEAP_DUMP_DATA_SOURCE_STOP_TIMEOUT_MS_DEFAULT, 308 sJavaHeapDumpDataSourceStopTimeoutMsDefault); 309 sJavaHeapDumpSizeKbDefault = properties.getInt( 310 DeviceConfigHelper.JAVA_HEAP_DUMP_SIZE_KB_DEFAULT, sJavaHeapDumpSizeKbDefault); 311 sJavaHeapDumpSizeKbMin = properties.getInt( 312 DeviceConfigHelper.JAVA_HEAP_DUMP_SIZE_KB_MIN, sJavaHeapDumpSizeKbMin); 313 sJavaHeapDumpSizeKbMax = properties.getInt( 314 DeviceConfigHelper.JAVA_HEAP_DUMP_SIZE_KB_MAX, sJavaHeapDumpSizeKbMax); 315 } 316 317 if (sStackSamplingConfigsInitialized) { 318 sKillswitchStackSampling = properties.getBoolean( 319 DeviceConfigHelper.KILLSWITCH_STACK_SAMPLING, sKillswitchStackSampling); 320 sStackSamplingFlushTimeoutMsDefault = properties.getInt( 321 DeviceConfigHelper.STACK_SAMPLING_FLUSH_TIMEOUT_MS_DEFAULT, 322 sStackSamplingFlushTimeoutMsDefault); 323 sStackSamplingDurationMsDefault = properties.getInt( 324 DeviceConfigHelper.STACK_SAMPLING_DURATION_MS_DEFAULT, 325 sStackSamplingDurationMsDefault); 326 sStackSamplingDurationMsMin = properties.getInt( 327 DeviceConfigHelper.STACK_SAMPLING_DURATION_MS_MIN, sStackSamplingDurationMsMin); 328 sStackSamplingDurationMsMax = properties.getInt( 329 DeviceConfigHelper.STACK_SAMPLING_DURATION_MS_MAX, sStackSamplingDurationMsMax); 330 sStackSamplingSizeKbDefault = properties.getInt( 331 DeviceConfigHelper.STACK_SAMPLING_SAMPLING_SIZE_KB_DEFAULT, 332 sStackSamplingSizeKbDefault); 333 sStackSamplingSizeKbMin = properties.getInt( 334 DeviceConfigHelper.STACK_SAMPLING_SAMPLING_SIZE_KB_MIN, 335 sStackSamplingSizeKbMin); 336 sStackSamplingSizeKbMax = properties.getInt( 337 DeviceConfigHelper.STACK_SAMPLING_SAMPLING_SIZE_KB_MAX, 338 sStackSamplingSizeKbMax); 339 sStackSamplingSamplingFrequencyDefault = properties.getInt( 340 DeviceConfigHelper.STACK_SAMPLING_FREQUENCY_DEFAULT, 341 sStackSamplingSamplingFrequencyDefault); 342 sStackSamplingSamplingFrequencyMin = properties.getInt( 343 DeviceConfigHelper.STACK_SAMPLING_FREQUENCY_MIN, 344 sStackSamplingSamplingFrequencyMin); 345 sStackSamplingSamplingFrequencyMax = properties.getInt( 346 DeviceConfigHelper.STACK_SAMPLING_FREQUENCY_MAX, 347 sStackSamplingSamplingFrequencyMax); 348 } 349 } 350 351 /** This method transforms a request into a useable config for perfetto. */ generateConfigForRequest(int profilingType, final @Nullable Bundle params, String packageName)352 public static byte[] generateConfigForRequest(int profilingType, final @Nullable Bundle params, 353 String packageName) throws IllegalArgumentException { 354 // Create a copy to modify. Entries will be removed from the copy as they're accessed to 355 // ensure that no invalid parameters are present. 356 Bundle paramsCopy = params == null ? null : new Bundle(params); 357 358 switch (profilingType) { 359 // Java heap dump 360 case ProfilingManager.PROFILING_TYPE_JAVA_HEAP_DUMP: 361 // This should be unnecessary, but make sure configs are initialized just in case. 362 initializeJavaHeapDumpConfigsIfNecessary(); 363 364 if (sKillswitchJavaHeapDump) { 365 throw new IllegalArgumentException("Java heap dump is disabled"); 366 } 367 368 int javaHeapDumpSizeKb = roundUpForBufferSize(getAndRemoveWithinBounds( 369 ProfilingManager.KEY_SIZE_KB, 370 sJavaHeapDumpSizeKbDefault, 371 sJavaHeapDumpSizeKbMin, 372 sJavaHeapDumpSizeKbMax, 373 paramsCopy)); 374 375 confirmEmptyOrThrow(paramsCopy); 376 377 return generateJavaHeapDumpConfig(packageName, javaHeapDumpSizeKb); 378 379 // Heap profile 380 case ProfilingManager.PROFILING_TYPE_HEAP_PROFILE: 381 // This should be unnecessary, but make sure configs are initialized just in case. 382 initializeHeapProfileConfigsIfNecessary(); 383 384 if (sKillswitchHeapProfile) { 385 throw new IllegalArgumentException("Heap profile is disabled"); 386 } 387 388 boolean trackJavaAllocations = getAndRemove( 389 ProfilingManager.KEY_TRACK_JAVA_ALLOCATIONS, 390 sHeapProfileTrackJavaAllocationsDefault, paramsCopy); 391 long samplingIntervalBytes = getAndRemoveWithinBounds( 392 ProfilingManager.KEY_SAMPLING_INTERVAL_BYTES, 393 sHeapProfileSamplingIntervalBytesDefault, 394 sHeapProfileSamplingIntervalBytesMin, 395 sHeapProfileSamplingIntervalBytesMax, 396 paramsCopy); 397 int heapProfileDurationMs = getAndRemoveWithinBounds( 398 ProfilingManager.KEY_DURATION_MS, 399 sHeapProfileDurationMsDefault, 400 sHeapProfileDurationMsMin, 401 sHeapProfileDurationMsMax, 402 paramsCopy); 403 int heapProfileSizeKb = roundUpForBufferSize(getAndRemoveWithinBounds( 404 ProfilingManager.KEY_SIZE_KB, 405 sHeapProfileSizeKbDefault, 406 sHeapProfileSizeKbMin, 407 sHeapProfileSizeKbMax, 408 paramsCopy)); 409 410 confirmEmptyOrThrow(paramsCopy); 411 412 return generateHeapProfileConfig(packageName, heapProfileSizeKb, 413 heapProfileDurationMs, samplingIntervalBytes, trackJavaAllocations); 414 415 // Stack sampling 416 case ProfilingManager.PROFILING_TYPE_STACK_SAMPLING: 417 // This should be unnecessary, but make sure configs are initialized just in case. 418 initializeStackSamplingConfigsIfNecessary(); 419 420 if (sKillswitchStackSampling) { 421 throw new IllegalArgumentException("Stack sampling is disabled"); 422 } 423 424 long frequency = getAndRemoveWithinBounds(ProfilingManager.KEY_FREQUENCY_HZ, 425 sStackSamplingSamplingFrequencyDefault, 426 sStackSamplingSamplingFrequencyMin, 427 sStackSamplingSamplingFrequencyMax, 428 paramsCopy); 429 int stackSamplingDurationMs = getAndRemoveWithinBounds( 430 ProfilingManager.KEY_DURATION_MS, 431 sStackSamplingDurationMsDefault, 432 sStackSamplingDurationMsMin, 433 sStackSamplingDurationMsMax, 434 paramsCopy); 435 int stackSamplingSizeKb = roundUpForBufferSize(getAndRemoveWithinBounds( 436 ProfilingManager.KEY_SIZE_KB, 437 sStackSamplingSizeKbDefault, 438 sStackSamplingSizeKbMin, 439 sStackSamplingSizeKbMax, 440 paramsCopy)); 441 442 confirmEmptyOrThrow(paramsCopy); 443 444 return generateStackSamplingConfig(packageName, stackSamplingSizeKb, 445 stackSamplingDurationMs, frequency); 446 447 // System trace 448 case ProfilingManager.PROFILING_TYPE_SYSTEM_TRACE: 449 // This should be unnecessary, but make sure configs are initialized just in case. 450 initializeSystemTraceConfigsIfNecessary(); 451 452 if (sKillswitchSystemTrace) { 453 throw new IllegalArgumentException("System trace is disabled"); 454 } 455 456 int systemTraceDurationMs = getAndRemoveWithinBounds( 457 ProfilingManager.KEY_DURATION_MS, 458 sSystemTraceDurationMsDefault, 459 sSystemTraceDurationMsMin, 460 sSystemTraceDurationMsMax, 461 paramsCopy); 462 int systemTraceSizeKb = roundUpForBufferSize(getAndRemoveWithinBounds( 463 ProfilingManager.KEY_SIZE_KB, 464 sSystemTraceSizeKbDefault, 465 sSystemTraceSizeKbMin, 466 sSystemTraceSizeKbMax, 467 paramsCopy)); 468 TraceConfig.BufferConfig.FillPolicy systemTraceBufferFillPolicy = 469 getBufferFillPolicy(getAndRemove(ProfilingManager.KEY_BUFFER_FILL_POLICY, 470 ProfilingManager.VALUE_BUFFER_FILL_POLICY_RING_BUFFER, paramsCopy)); 471 472 confirmEmptyOrThrow(paramsCopy); 473 474 return generateSystemTraceConfig(packageName, systemTraceSizeKb, 475 systemTraceDurationMs, systemTraceBufferFillPolicy); 476 477 // Invalid type 478 default: 479 throw new IllegalArgumentException("Invalid profiling type"); 480 } 481 } 482 483 /** 484 * This method returns how long in ms to wait initially before checking if profiling is complete 485 * and rescheduling another check or post processing and cleaning up the result in the event 486 * that it's not stopped manually. 487 */ getInitialProfilingTimeMs(int profilingType, @Nullable Bundle params)488 public static int getInitialProfilingTimeMs(int profilingType, 489 @Nullable Bundle params) { 490 int duration; 491 switch (profilingType) { 492 case ProfilingManager.PROFILING_TYPE_JAVA_HEAP_DUMP: 493 initializeJavaHeapDumpConfigsIfNecessary(); 494 duration = sJavaHeapDumpDurationMsDefault; 495 break; 496 497 case ProfilingManager.PROFILING_TYPE_HEAP_PROFILE: 498 initializeHeapProfileConfigsIfNecessary(); 499 duration = getWithinBounds(ProfilingManager.KEY_DURATION_MS, 500 sHeapProfileDurationMsDefault, sHeapProfileDurationMsMin, 501 sHeapProfileDurationMsMax, params); 502 break; 503 504 case ProfilingManager.PROFILING_TYPE_STACK_SAMPLING: 505 initializeStackSamplingConfigsIfNecessary(); 506 duration = getWithinBounds(ProfilingManager.KEY_DURATION_MS, 507 sStackSamplingDurationMsDefault, sStackSamplingDurationMsMin, 508 sStackSamplingDurationMsMax, params); 509 break; 510 511 case ProfilingManager.PROFILING_TYPE_SYSTEM_TRACE: 512 initializeSystemTraceConfigsIfNecessary(); 513 duration = getWithinBounds(ProfilingManager.KEY_DURATION_MS, 514 sSystemTraceDurationMsDefault, sSystemTraceDurationMsMin, 515 sSystemTraceDurationMsMax, params); 516 break; 517 518 default: 519 throw new IllegalArgumentException("Invalid profiling type"); 520 } 521 return duration + FILE_PROCESSING_DELAY_MS; 522 } 523 524 /** 525 * This method returns the maximum profiling time allowed for the different profiling types. 526 */ getMaxProfilingTimeAllowedMs(int profilingType, @Nullable Bundle params)527 public static int getMaxProfilingTimeAllowedMs(int profilingType, @Nullable Bundle params) { 528 // Get the initial delay 529 int maxAllowedProcessingTime = 530 getInitialProfilingTimeMs(profilingType, params); 531 532 // Add the respective flush and data source timeouts for the types that have them. 533 switch (profilingType) { 534 case ProfilingManager.PROFILING_TYPE_HEAP_PROFILE: 535 maxAllowedProcessingTime += sHeapProfileFlushTimeoutMsDefault; 536 break; 537 538 case ProfilingManager.PROFILING_TYPE_JAVA_HEAP_DUMP: 539 maxAllowedProcessingTime += sJavaHeapDumpDataSourceStopTimeoutMsDefault; 540 break; 541 542 case ProfilingManager.PROFILING_TYPE_STACK_SAMPLING: 543 maxAllowedProcessingTime += sStackSamplingFlushTimeoutMsDefault; 544 break; 545 } 546 // Add extra buffer time to account for the time it may take to start the underlying 547 // process. 548 return maxAllowedProcessingTime + MAX_PROFILING_TIME_BUFFER_MS; 549 } 550 getBufferFillPolicy(int bufferFillPolicy)551 private static TraceConfig.BufferConfig.FillPolicy getBufferFillPolicy(int bufferFillPolicy) 552 throws IllegalArgumentException { 553 switch (bufferFillPolicy) { 554 case ProfilingManager.VALUE_BUFFER_FILL_POLICY_DISCARD: 555 return TraceConfig.BufferConfig.FillPolicy.DISCARD; 556 case ProfilingManager.VALUE_BUFFER_FILL_POLICY_RING_BUFFER: 557 return TraceConfig.BufferConfig.FillPolicy.RING_BUFFER; 558 default: 559 throw new IllegalArgumentException("Invalid buffer fill policy."); 560 } 561 } 562 getWithinBounds(String key, int defaultValue, int minValue, int maxValue, @Nullable Bundle params)563 private static int getWithinBounds(String key, int defaultValue, int minValue, 564 int maxValue, @Nullable Bundle params) { 565 if (params == null) { 566 return defaultValue; 567 } 568 int value = params.getInt(key, defaultValue); 569 if (value < minValue) { 570 return minValue; 571 } else if (value > maxValue) { 572 return maxValue; 573 } else { 574 return value; 575 } 576 } 577 getAndRemove(String key, boolean defaultValue, @Nullable Bundle bundle)578 private static boolean getAndRemove(String key, boolean defaultValue, @Nullable Bundle bundle) { 579 if (bundle == null) { 580 return defaultValue; 581 } 582 if (bundle.containsKey(key)) { 583 boolean value = bundle.getBoolean(key); 584 bundle.remove(key); 585 return value; 586 } 587 return defaultValue; 588 } 589 getAndRemove(String key, int defaultValue, @Nullable Bundle bundle)590 private static int getAndRemove(String key, int defaultValue, @Nullable Bundle bundle) { 591 if (bundle == null) { 592 return defaultValue; 593 } 594 if (bundle.containsKey(key)) { 595 int value = bundle.getInt(key); 596 bundle.remove(key); 597 return value; 598 } 599 return defaultValue; 600 } 601 getAndRemoveWithinBounds(String key, int defaultValue, int minValue, int maxValue, @Nullable Bundle bundle)602 private static int getAndRemoveWithinBounds(String key, int defaultValue, int minValue, 603 int maxValue, @Nullable Bundle bundle) { 604 if (bundle == null) { 605 return defaultValue; 606 } 607 if (bundle.containsKey(key)) { 608 int value = bundle.getInt(key); 609 bundle.remove(key); 610 if (value < minValue) { 611 value = minValue; 612 } else if (value > maxValue) { 613 value = maxValue; 614 } 615 return value; 616 } 617 return defaultValue; 618 } 619 getAndRemoveWithinBounds(String key, long defaultValue, long minValue, long maxValue, @Nullable Bundle bundle)620 private static long getAndRemoveWithinBounds(String key, long defaultValue, long minValue, 621 long maxValue, @Nullable Bundle bundle) { 622 if (bundle == null) { 623 return defaultValue; 624 } 625 if (bundle.containsKey(key)) { 626 long value = bundle.getLong(key); 627 bundle.remove(key); 628 if (value < minValue) { 629 value = minValue; 630 } else if (value > maxValue) { 631 value = maxValue; 632 } 633 return value; 634 } 635 return defaultValue; 636 } 637 638 /** Buffer sizes are preferred to be multiples of 4kb, round up to next lowest 4 multiple. */ roundUpForBufferSize(int bufferSize)639 private static int roundUpForBufferSize(int bufferSize) { 640 return (bufferSize % 4 == 0) ? bufferSize : bufferSize + (4 - (bufferSize % 4)); 641 } 642 confirmEmptyOrThrow(@ullable Bundle bundle)643 private static void confirmEmptyOrThrow(@Nullable Bundle bundle) 644 throws IllegalArgumentException { 645 if (bundle != null && !bundle.isEmpty()) { 646 throw new IllegalArgumentException( 647 "Bundle contains invalid or unsupported parameters"); 648 } 649 } 650 generateJavaHeapDumpConfig(String packageName, int bufferSizeKb)651 private static byte[] generateJavaHeapDumpConfig(String packageName, int bufferSizeKb) { 652 TraceConfig.Builder builder = TraceConfig.newBuilder(); 653 654 // Add a buffer 655 TraceConfig.BufferConfig buffer = TraceConfig.BufferConfig.newBuilder() 656 .setSizeKb(bufferSizeKb) 657 .setFillPolicy(TraceConfig.BufferConfig.FillPolicy.DISCARD) 658 .build(); 659 builder.addBuffers(buffer); 660 661 // Add data source 662 JavaHprofConfig javaHprofConfig = JavaHprofConfig.newBuilder() 663 .addProcessCmdline(packageName) 664 .setDumpSmaps(true) 665 .build(); 666 DataSourceConfig dataSourceConfig = DataSourceConfig.newBuilder() 667 .setName("android.java_hprof") 668 .setJavaHprofConfig(javaHprofConfig) 669 .build(); 670 TraceConfig.DataSource dataSource = TraceConfig.DataSource.newBuilder() 671 .setConfig(dataSourceConfig) 672 .build(); 673 builder.addDataSources(dataSource); 674 675 // Add duration and timeout 676 builder.setDurationMs(sJavaHeapDumpDurationMsDefault); 677 builder.setDataSourceStopTimeoutMs(sJavaHeapDumpDataSourceStopTimeoutMsDefault); 678 679 return builder.build().toByteArray(); 680 } 681 generateHeapProfileConfig(String packageName, int bufferSizeKb, int durationMs, long samplingIntervalBytes, boolean trackJavaAllocations)682 private static byte[] generateHeapProfileConfig(String packageName, int bufferSizeKb, 683 int durationMs, long samplingIntervalBytes, boolean trackJavaAllocations) { 684 TraceConfig.Builder builder = TraceConfig.newBuilder(); 685 686 // Add a buffer 687 TraceConfig.BufferConfig buffer = TraceConfig.BufferConfig.newBuilder() 688 .setSizeKb(bufferSizeKb) 689 .setFillPolicy(TraceConfig.BufferConfig.FillPolicy.DISCARD) 690 .build(); 691 builder.addBuffers(buffer); 692 693 // Add data source 694 HeapprofdConfig.Builder heapprofdConfigBuilder = HeapprofdConfig.newBuilder() 695 .setShmemSizeBytes(8388608) //8MB 696 .setSamplingIntervalBytes(samplingIntervalBytes) 697 .addProcessCmdline(packageName); 698 if (trackJavaAllocations) { 699 heapprofdConfigBuilder.addHeaps("com.android.art"); 700 } 701 DataSourceConfig dataSourceConfig = DataSourceConfig.newBuilder() 702 .setName("android.heapprofd") 703 .setHeapprofdConfig(heapprofdConfigBuilder.build()) 704 .build(); 705 TraceConfig.DataSource dataSource = TraceConfig.DataSource.newBuilder() 706 .setConfig(dataSourceConfig) 707 .build(); 708 builder.addDataSources(dataSource); 709 710 // Add duration and timeout 711 builder.setDurationMs(durationMs); 712 builder.setFlushTimeoutMs(sHeapProfileFlushTimeoutMsDefault); 713 714 return builder.build().toByteArray(); 715 } 716 generateStackSamplingConfig(String packageName, int bufferSizeKb, int durationMs, long frequency)717 private static byte[] generateStackSamplingConfig(String packageName, int bufferSizeKb, 718 int durationMs, long frequency) { 719 TraceConfig.Builder builder = TraceConfig.newBuilder(); 720 721 // Add a buffer 722 TraceConfig.BufferConfig buffer = TraceConfig.BufferConfig.newBuilder() 723 .setSizeKb(bufferSizeKb) 724 .setFillPolicy(TraceConfig.BufferConfig.FillPolicy.DISCARD) 725 .build(); 726 builder.addBuffers(buffer); 727 728 // Add data source 729 PerfEvents.Timebase timebase = PerfEvents.Timebase.newBuilder() 730 .setCounter(PerfEvents.Counter.SW_CPU_CLOCK) 731 .setFrequency(frequency) 732 .setTimestampClock(PerfEvents.PerfClock.PERF_CLOCK_MONOTONIC) 733 .build(); 734 PerfEventConfig.Scope scope = PerfEventConfig.Scope.newBuilder() 735 .addTargetCmdline(packageName) 736 .build(); 737 PerfEventConfig.CallstackSampling callstackSampling = PerfEventConfig.CallstackSampling 738 .newBuilder() 739 .setScope(scope) 740 .build(); 741 PerfEventConfig perfEventConfig = PerfEventConfig.newBuilder() 742 .setTimebase(timebase) 743 .setCallstackSampling(callstackSampling) 744 .build(); 745 DataSourceConfig dataSourceConfig = DataSourceConfig.newBuilder() 746 .setName("linux.perf") 747 .setPerfEventConfig(perfEventConfig) 748 .build(); 749 TraceConfig.DataSource dataSource = TraceConfig.DataSource.newBuilder() 750 .setConfig(dataSourceConfig) 751 .build(); 752 builder.addDataSources(dataSource); 753 754 // Add duration and timeout 755 builder.setDurationMs(durationMs); 756 builder.setFlushTimeoutMs(sStackSamplingFlushTimeoutMsDefault); 757 758 return builder.build().toByteArray(); 759 } 760 generateSystemTraceConfig(String packageName, int bufferSizeKb, int durationMs, TraceConfig.BufferConfig.FillPolicy bufferFillPolicy)761 private static byte[] generateSystemTraceConfig(String packageName, int bufferSizeKb, 762 int durationMs, TraceConfig.BufferConfig.FillPolicy bufferFillPolicy) { 763 TraceConfig.Builder builder = TraceConfig.newBuilder(); 764 765 addSystemTraceGeneralConfigs( 766 builder, 767 new String[] {packageName}, 768 FOUR_MB, 769 bufferSizeKb, 770 durationMs, 771 bufferFillPolicy); 772 773 return builder.build().toByteArray(); 774 } 775 776 /** 777 * Generate config for system triggered background system trace. 778 * 779 * @param extraLong should only be set to true for testing. 780 */ generateSystemTriggeredTraceConfig(String uniqueSessionName, String[] packageNames, boolean extraLong)781 public static byte[] generateSystemTriggeredTraceConfig(String uniqueSessionName, 782 String[] packageNames, boolean extraLong) { 783 // Make sure we have our config values set. This is the only config specific method which is 784 // called directly and therefore needs to verify the config value initialization directly. 785 initializeSystemTriggeredSystemTraceConfigsIfNecessary(); 786 787 TraceConfig.Builder builder = TraceConfig.newBuilder(); 788 789 addSystemTraceGeneralConfigs( 790 builder, 791 packageNames, 792 sSystemTriggeredSystemTraceDiscardBufferSizeKb, 793 sSystemTriggeredSystemTraceRingBufferSizeKb, 794 extraLong 795 ? ONE_DAY_MS 796 : sSystemTriggeredSystemTraceDurationMs, 797 TraceConfig.BufferConfig.FillPolicy.RING_BUFFER); 798 799 builder.setUniqueSessionName(uniqueSessionName); 800 801 return builder.build().toByteArray(); 802 } 803 addSystemTraceGeneralConfigs(TraceConfig.Builder builder, String[] packageNames, int bufferOneSizeKb, int bufferTwoSizeKb, int durationMs, TraceConfig.BufferConfig.FillPolicy bufferTwoFillPolicy)804 private static void addSystemTraceGeneralConfigs(TraceConfig.Builder builder, 805 String[] packageNames, int bufferOneSizeKb, int bufferTwoSizeKb, int durationMs, 806 TraceConfig.BufferConfig.FillPolicy bufferTwoFillPolicy) { 807 // Add 2 buffers, discard for data sources dumped at beginning and caller set for all other 808 // data sources. 809 TraceConfig.BufferConfig buffer0 = TraceConfig.BufferConfig.newBuilder() 810 .setSizeKb(bufferOneSizeKb) 811 .setFillPolicy(TraceConfig.BufferConfig.FillPolicy.DISCARD) 812 .build(); 813 builder.addBuffers(buffer0); 814 TraceConfig.BufferConfig buffer1 = TraceConfig.BufferConfig.newBuilder() 815 .setSizeKb(bufferTwoSizeKb) 816 .setFillPolicy(bufferTwoFillPolicy) 817 .build(); 818 builder.addBuffers(buffer1); 819 820 // Add a whole bunch of data sources 821 822 // Scan and dump all processes to buffer 0 when trace starts 823 ProcessStatsConfig processStatsConfig = ProcessStatsConfig.newBuilder() 824 .setScanAllProcessesOnStart(true) 825 .build(); 826 DataSourceConfig dataSourceConfigProcessStats = DataSourceConfig.newBuilder() 827 .setName("linux.process_stats") 828 .setTargetBuffer(0) 829 .setProcessStatsConfig(processStatsConfig) 830 .build(); 831 TraceConfig.DataSource dataSourceProcessStats = TraceConfig.DataSource.newBuilder() 832 .setConfig(dataSourceConfigProcessStats) 833 .build(); 834 builder.addDataSources(dataSourceProcessStats); 835 836 // Initialize the builders that require package names so we only need to iterate through the 837 // list once. These will be used in the following two sections. 838 PackagesListConfig.Builder packagesListConfigBuilder = PackagesListConfig.newBuilder(); 839 FtraceConfig.Builder ftraceConfigBuilder = FtraceConfig.newBuilder(); 840 841 for (int i = 0; i < packageNames.length; i++) { 842 String packageName = packageNames[i]; 843 844 // Enable atrace events for each app. 845 ftraceConfigBuilder.addAtraceApps(packageName); 846 847 // Add to package list config so data is kept by filter. 848 packagesListConfigBuilder.addPackageNameFilter(packageName); 849 } 850 851 // Dump details about all listed packages to buffer 0. Redactor will filter out the ones 852 // that should not end up in the finished output. 853 DataSourceConfig dataSourceConfigPackagesList = DataSourceConfig.newBuilder() 854 .setName("android.packages_list") 855 .setTargetBuffer(0) 856 .setPackagesListConfig(packagesListConfigBuilder.build()) 857 .build(); 858 TraceConfig.DataSource dataSourcePackagesList = TraceConfig.DataSource.newBuilder() 859 .setConfig(dataSourceConfigPackagesList) 860 .build(); 861 builder.addDataSources(dataSourcePackagesList); 862 863 // Dump select ftrace events to buffer 1 864 FtraceConfig.CompactSchedConfig compactSchedConfig = FtraceConfig.CompactSchedConfig 865 .newBuilder() 866 .setEnabled(true) 867 .build(); 868 ftraceConfigBuilder 869 .setThrottleRssStat(true) 870 .setDisableGenericEvents(true) 871 .setCompactSched(compactSchedConfig) 872 // RSS and ION buffer events: 873 .addFtraceEvents("gpu_mem/gpu_mem_total") 874 // Scheduling information & process tracking. Useful for: 875 // - what is happening on each CPU at each moment 876 // - why a thread was descheduled 877 // - parent/child relationships between processes and threads 878 .addFtraceEvents("power/suspend_resume") 879 .addFtraceEvents("sched/sched_process_free") 880 .addFtraceEvents("sched/sched_switch") 881 .addFtraceEvents("task/task_newtask") 882 .addFtraceEvents("task/task_rename") 883 // Wakeup info. Allows you to compute how long a task was: 884 .addFtraceEvents("sched/sched_waking") 885 .addFtraceEvents("sched/sched_wakeup_new") 886 // vmscan and mm_compaction events: 887 .addFtraceEvents("vmscan/mm_vmscan_direct_reclaim_begin") 888 .addFtraceEvents("vmscan/mm_vmscan_direct_reclaim_end") 889 // Atrace activity manager: 890 .addAtraceCategories("am") 891 // Java and C: 892 .addAtraceCategories("dalvik") 893 // Bionic C library: 894 .addAtraceCategories("bionic") 895 // Binder kernel driver 896 .addAtraceCategories("binder_driver") 897 // View system: 898 .addAtraceCategories("view") 899 // Input: 900 .addAtraceCategories("input") 901 // Graphics: 902 .addAtraceCategories("gfx"); 903 904 DataSourceConfig dataSourceConfigFtrace = DataSourceConfig.newBuilder() 905 .setName("linux.ftrace") 906 .setTargetBuffer(1) 907 .setFtraceConfig(ftraceConfigBuilder.build()) 908 .build(); 909 TraceConfig.DataSource dataSourceFtrace = TraceConfig.DataSource.newBuilder() 910 .setConfig(dataSourceConfigFtrace) 911 .build(); 912 builder.addDataSources(dataSourceFtrace); 913 914 // Dump surfaceflinger frame timeline to buffer 1 915 DataSourceConfig dataSourceConfigSurfaceFlinger = DataSourceConfig.newBuilder() 916 .setName("android.surfaceflinger.frametimeline") 917 .setTargetBuffer(1) 918 .build(); 919 TraceConfig.DataSource dataSourceSurfaceFlinger = TraceConfig.DataSource.newBuilder() 920 .setConfig(dataSourceConfigSurfaceFlinger) 921 .build(); 922 builder.addDataSources(dataSourceSurfaceFlinger); 923 924 // Clear incremental state 925 TraceConfig.IncrementalStateConfig incrementalStateConfig = TraceConfig 926 .IncrementalStateConfig.newBuilder() 927 .setClearPeriodMs(10000) 928 .build(); 929 builder.setIncrementalStateConfig(incrementalStateConfig); 930 931 // Add duration 932 builder.setDurationMs(durationMs); 933 } 934 935 } 936