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