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 dev.perfetto.sdk; 18 19 import dalvik.annotation.optimization.CriticalNative; 20 import dalvik.annotation.optimization.FastNative; 21 22 import java.util.ArrayList; 23 import java.util.List; 24 import java.util.concurrent.atomic.AtomicLong; 25 import java.util.function.Supplier; 26 27 /** 28 * Holds extras to be passed to Perfetto track events in {@link PerfettoTrace}. 29 * 30 * @hide 31 */ 32 public final class PerfettoTrackEventExtra { 33 private static final boolean DEBUG = false; 34 private static final int DEFAULT_EXTRA_CACHE_SIZE = 5; 35 private static final Builder NO_OP_BUILDER = new Builder(/* extra= */ null, /* isCategoryEnabled= */ false); 36 private static final ThreadLocal<PerfettoTrackEventExtra> sTrackEventExtra = 37 new ThreadLocal<PerfettoTrackEventExtra>() { 38 @Override 39 protected PerfettoTrackEventExtra initialValue() { 40 return new PerfettoTrackEventExtra(); 41 } 42 }; 43 private static final AtomicLong sNamedTrackId = new AtomicLong(); 44 private static final Supplier<Flow> sFlowSupplier = Flow::new; 45 private static final Supplier<Builder> sBuilderSupplier = Builder::new; 46 private static final Supplier<FieldInt64> sFieldInt64Supplier = FieldInt64::new; 47 private static final Supplier<FieldDouble> sFieldDoubleSupplier = FieldDouble::new; 48 private static final Supplier<FieldString> sFieldStringSupplier = FieldString::new; 49 private static final Supplier<FieldNested> sFieldNestedSupplier = FieldNested::new; 50 51 private final List<PerfettoPointer> mPendingPointers = new ArrayList<>(); 52 private CounterInt64 mCounterInt64; 53 private CounterDouble mCounterDouble; 54 private Proto mProto; 55 private Flow mFlow; 56 private Flow mTerminatingFlow; 57 58 static class NativeAllocationRegistry { createMalloced( ClassLoader classLoader, long freeFunction)59 public static NativeAllocationRegistry createMalloced( 60 ClassLoader classLoader, long freeFunction) { 61 // do nothing 62 return new NativeAllocationRegistry(); 63 } registerNativeAllocation(Object obj, long ptr)64 public void registerNativeAllocation(Object obj, long ptr) { 65 // do nothing 66 } 67 } 68 69 /** 70 * Represents a native pointer to a Perfetto C SDK struct. E.g. PerfettoTeHlExtra. 71 */ 72 public interface PerfettoPointer { 73 /** 74 * Returns the perfetto struct native pointer. 75 */ getPtr()76 long getPtr(); 77 } 78 79 /** 80 * Container for {@link Field} instances. 81 */ 82 public interface FieldContainer { 83 /** 84 * Add {@link Field} to the container. 85 */ addField(PerfettoPointer field)86 void addField(PerfettoPointer field); 87 } 88 89 /** 90 * RingBuffer implemented on top of a SparseArray. 91 * 92 * Bounds a SparseArray with a FIFO algorithm. 93 */ 94 private static final class RingBuffer<T> { 95 private final int mCapacity; 96 private final int[] mKeyArray; 97 private final T[] mValueArray; 98 private int mWriteEnd = 0; 99 RingBuffer(int capacity)100 RingBuffer(int capacity) { 101 mCapacity = capacity; 102 mKeyArray = new int[capacity]; 103 mValueArray = (T[]) new Object[capacity]; 104 } 105 put(int key, T value)106 public void put(int key, T value) { 107 mKeyArray[mWriteEnd] = key; 108 mValueArray[mWriteEnd] = value; 109 mWriteEnd = (mWriteEnd + 1) % mCapacity; 110 } 111 get(int key)112 public T get(int key) { 113 for (int i = 0; i < mCapacity; i++) { 114 if (mKeyArray[i] == key) { 115 return mValueArray[i]; 116 } 117 } 118 return null; 119 } 120 } 121 122 private static final class Pool<T> { 123 private final int mCapacity; 124 private final T[] mValueArray; 125 private int mIdx = 0; 126 Pool(int capacity)127 Pool(int capacity) { 128 mCapacity = capacity; 129 mValueArray = (T[]) new Object[capacity]; 130 } 131 reset()132 public void reset() { 133 mIdx = 0; 134 } 135 get(Supplier<T> supplier)136 public T get(Supplier<T> supplier) { 137 if (mIdx >= mCapacity) { 138 return supplier.get(); 139 } 140 if (mValueArray[mIdx] == null) { 141 mValueArray[mIdx] = supplier.get(); 142 } 143 return mValueArray[mIdx++]; 144 } 145 } 146 147 /** 148 * Builder for Perfetto track event extras. 149 */ 150 public static final class Builder { 151 // For performance reasons, we hold a reference to mExtra as a holder for 152 // perfetto pointers being added. This way, we avoid an additional list to hold 153 // the pointers in Java and we can pass them down directly to native code. 154 private final PerfettoTrackEventExtra mExtra; 155 156 private int mTraceType; 157 private PerfettoTrace.Category mCategory; 158 private String mEventName; 159 private boolean mIsBuilt; 160 161 private Builder mParent; 162 private FieldContainer mCurrentContainer; 163 164 private final boolean mIsCategoryEnabled; 165 private final CounterInt64 mCounterInt64; 166 private final CounterDouble mCounterDouble; 167 private final Proto mProto; 168 private final Flow mFlow; 169 private final Flow mTerminatingFlow; 170 171 private final RingBuffer<NamedTrack> mNamedTrackCache; 172 private final RingBuffer<CounterTrack> mCounterTrackCache; 173 private final RingBuffer<ArgInt64> mArgInt64Cache; 174 private final RingBuffer<ArgBool> mArgBoolCache; 175 private final RingBuffer<ArgDouble> mArgDoubleCache; 176 private final RingBuffer<ArgString> mArgStringCache; 177 178 private final Pool<FieldInt64> mFieldInt64Cache; 179 private final Pool<FieldDouble> mFieldDoubleCache; 180 private final Pool<FieldString> mFieldStringCache; 181 private final Pool<FieldNested> mFieldNestedCache; 182 private final Pool<Builder> mBuilderCache; 183 Builder()184 private Builder() { 185 this(sTrackEventExtra.get(), true); 186 } 187 Builder(PerfettoTrackEventExtra extra, boolean isCategoryEnabled)188 public Builder(PerfettoTrackEventExtra extra, boolean isCategoryEnabled) { 189 mIsCategoryEnabled = isCategoryEnabled; 190 mExtra = extra; 191 mNamedTrackCache = mExtra == null ? null : mExtra.mNamedTrackCache; 192 mCounterTrackCache = mExtra == null ? null : mExtra.mCounterTrackCache; 193 mArgInt64Cache = mExtra == null ? null : mExtra.mArgInt64Cache; 194 mArgDoubleCache = mExtra == null ? null : mExtra.mArgDoubleCache; 195 mArgBoolCache = mExtra == null ? null : mExtra.mArgBoolCache; 196 mArgStringCache = mExtra == null ? null : mExtra.mArgStringCache; 197 mFieldInt64Cache = mExtra == null ? null : mExtra.mFieldInt64Cache; 198 mFieldDoubleCache = mExtra == null ? null : mExtra.mFieldDoubleCache; 199 mFieldStringCache = mExtra == null ? null : mExtra.mFieldStringCache; 200 mFieldNestedCache = mExtra == null ? null : mExtra.mFieldNestedCache; 201 mBuilderCache = mExtra == null ? null : mExtra.mBuilderCache; 202 203 mCounterInt64 = mExtra == null ? null : mExtra.getCounterInt64(); 204 mCounterDouble = mExtra == null ? null : mExtra.getCounterDouble(); 205 mProto = mExtra == null ? null : mExtra.getProto(); 206 mFlow = mExtra == null ? null : mExtra.getFlow(); 207 mTerminatingFlow = mExtra == null ? null : mExtra.getTerminatingFlow(); 208 } 209 210 /** 211 * Emits the track event. 212 */ emit()213 public void emit() { 214 if (!mIsCategoryEnabled) { 215 return; 216 } 217 if (DEBUG) { 218 checkParent(); 219 } 220 221 mIsBuilt = true; 222 native_emit(mTraceType, mCategory.getPtr(), mEventName, mExtra.getPtr()); 223 } 224 225 /** 226 * Initialize the builder for a new trace event. 227 */ init(int traceType, PerfettoTrace.Category category)228 public Builder init(int traceType, PerfettoTrace.Category category) { 229 if (!mIsCategoryEnabled) { 230 return this; 231 } 232 233 mTraceType = traceType; 234 mCategory = category; 235 mEventName = ""; 236 mFieldInt64Cache.reset(); 237 mFieldDoubleCache.reset(); 238 mFieldStringCache.reset(); 239 mFieldNestedCache.reset(); 240 mBuilderCache.reset(); 241 242 mExtra.reset(); 243 // Reset after on init in case the thread created builders without calling emit 244 return initInternal(this, null); 245 } 246 247 /** 248 * Sets the event name for the track event. 249 */ setEventName(String eventName)250 public Builder setEventName(String eventName) { 251 mEventName = eventName; 252 return this; 253 } 254 255 /** 256 * Adds a debug arg with key {@code name} and value {@code val}. 257 */ addArg(String name, long val)258 public Builder addArg(String name, long val) { 259 if (!mIsCategoryEnabled) { 260 return this; 261 } 262 if (DEBUG) { 263 checkParent(); 264 } 265 ArgInt64 arg = mArgInt64Cache.get(name.hashCode()); 266 if (arg == null || !arg.getName().equals(name)) { 267 arg = new ArgInt64(name); 268 mArgInt64Cache.put(name.hashCode(), arg); 269 } 270 arg.setValue(val); 271 mExtra.addPerfettoPointer(arg); 272 return this; 273 } 274 275 /** 276 * Adds a debug arg with key {@code name} and value {@code val}. 277 */ addArg(String name, boolean val)278 public Builder addArg(String name, boolean val) { 279 if (!mIsCategoryEnabled) { 280 return this; 281 } 282 if (DEBUG) { 283 checkParent(); 284 } 285 ArgBool arg = mArgBoolCache.get(name.hashCode()); 286 if (arg == null || !arg.getName().equals(name)) { 287 arg = new ArgBool(name); 288 mArgBoolCache.put(name.hashCode(), arg); 289 } 290 arg.setValue(val); 291 mExtra.addPerfettoPointer(arg); 292 return this; 293 } 294 295 /** 296 * Adds a debug arg with key {@code name} and value {@code val}. 297 */ addArg(String name, double val)298 public Builder addArg(String name, double val) { 299 if (!mIsCategoryEnabled) { 300 return this; 301 } 302 if (DEBUG) { 303 checkParent(); 304 } 305 ArgDouble arg = mArgDoubleCache.get(name.hashCode()); 306 if (arg == null || !arg.getName().equals(name)) { 307 arg = new ArgDouble(name); 308 mArgDoubleCache.put(name.hashCode(), arg); 309 } 310 arg.setValue(val); 311 mExtra.addPerfettoPointer(arg); 312 return this; 313 } 314 315 /** 316 * Adds a debug arg with key {@code name} and value {@code val}. 317 */ addArg(String name, String val)318 public Builder addArg(String name, String val) { 319 if (!mIsCategoryEnabled) { 320 return this; 321 } 322 if (DEBUG) { 323 checkParent(); 324 } 325 ArgString arg = mArgStringCache.get(name.hashCode()); 326 if (arg == null || !arg.getName().equals(name)) { 327 arg = new ArgString(name); 328 mArgStringCache.put(name.hashCode(), arg); 329 } 330 arg.setValue(val); 331 mExtra.addPerfettoPointer(arg); 332 return this; 333 } 334 335 /** 336 * Adds a flow with {@code id}. 337 */ setFlow(long id)338 public Builder setFlow(long id) { 339 if (!mIsCategoryEnabled) { 340 return this; 341 } 342 if (DEBUG) { 343 checkParent(); 344 } 345 mFlow.setProcessFlow(id); 346 mExtra.addPerfettoPointer(mFlow); 347 return this; 348 } 349 350 /** 351 * Adds a terminating flow with {@code id}. 352 */ setTerminatingFlow(long id)353 public Builder setTerminatingFlow(long id) { 354 if (!mIsCategoryEnabled) { 355 return this; 356 } 357 if (DEBUG) { 358 checkParent(); 359 } 360 mTerminatingFlow.setProcessTerminatingFlow(id); 361 mExtra.addPerfettoPointer(mTerminatingFlow); 362 return this; 363 } 364 365 /** 366 * Adds the events to a named track instead of the thread track where the 367 * event occurred. 368 */ usingNamedTrack(long parentUuid, String name)369 public Builder usingNamedTrack(long parentUuid, String name) { 370 if (!mIsCategoryEnabled) { 371 return this; 372 } 373 if (DEBUG) { 374 checkParent(); 375 } 376 377 NamedTrack track = mNamedTrackCache.get(name.hashCode()); 378 if (track == null || !track.getName().equals(name)) { 379 track = new NamedTrack(name, parentUuid); 380 mNamedTrackCache.put(name.hashCode(), track); 381 } 382 mExtra.addPerfettoPointer(track); 383 return this; 384 } 385 386 /** 387 * Adds the events to a process scoped named track instead of the thread track where the 388 * event occurred. 389 */ usingProcessNamedTrack(String name)390 public Builder usingProcessNamedTrack(String name) { 391 if (!mIsCategoryEnabled) { 392 return this; 393 } 394 return usingNamedTrack(PerfettoTrace.getProcessTrackUuid(), name); 395 } 396 397 /** 398 * Adds the events to a thread scoped named track instead of the thread track where the 399 * event occurred. 400 */ usingThreadNamedTrack(long tid, String name)401 public Builder usingThreadNamedTrack(long tid, String name) { 402 if (!mIsCategoryEnabled) { 403 return this; 404 } 405 return usingNamedTrack(PerfettoTrace.getThreadTrackUuid(tid), name); 406 } 407 408 /** 409 * Adds the events to a counter track instead. This is required for 410 * setting counter values. 411 */ usingCounterTrack(long parentUuid, String name)412 public Builder usingCounterTrack(long parentUuid, String name) { 413 if (!mIsCategoryEnabled) { 414 return this; 415 } 416 if (DEBUG) { 417 checkParent(); 418 } 419 420 CounterTrack track = mCounterTrackCache.get(name.hashCode()); 421 if (track == null || !track.getName().equals(name)) { 422 track = new CounterTrack(name, parentUuid); 423 mCounterTrackCache.put(name.hashCode(), track); 424 } 425 mExtra.addPerfettoPointer(track); 426 return this; 427 } 428 429 /** 430 * Adds the events to a process scoped counter track instead. This is required for 431 * setting counter values. 432 */ usingProcessCounterTrack(String name)433 public Builder usingProcessCounterTrack(String name) { 434 if (!mIsCategoryEnabled) { 435 return this; 436 } 437 return usingCounterTrack(PerfettoTrace.getProcessTrackUuid(), name); 438 } 439 440 /** 441 * Adds the events to a thread scoped counter track instead. This is required for 442 * setting counter values. 443 */ usingThreadCounterTrack(long tid, String name)444 public Builder usingThreadCounterTrack(long tid, String name) { 445 if (!mIsCategoryEnabled) { 446 return this; 447 } 448 return usingCounterTrack(PerfettoTrace.getThreadTrackUuid(tid), name); 449 } 450 451 /** 452 * Sets a long counter value on the event. 453 * 454 */ setCounter(long val)455 public Builder setCounter(long val) { 456 if (!mIsCategoryEnabled) { 457 return this; 458 } 459 if (DEBUG) { 460 checkParent(); 461 } 462 mCounterInt64.setValue(val); 463 mExtra.addPerfettoPointer(mCounterInt64); 464 return this; 465 } 466 467 /** 468 * Sets a double counter value on the event. 469 * 470 */ setCounter(double val)471 public Builder setCounter(double val) { 472 if (!mIsCategoryEnabled) { 473 return this; 474 } 475 if (DEBUG) { 476 checkParent(); 477 } 478 mCounterDouble.setValue(val); 479 mExtra.addPerfettoPointer(mCounterDouble); 480 return this; 481 } 482 483 /** 484 * Adds a proto field with field id {@code id} and value {@code val}. 485 */ addField(long id, long val)486 public Builder addField(long id, long val) { 487 if (!mIsCategoryEnabled) { 488 return this; 489 } 490 if (DEBUG) { 491 checkContainer(); 492 } 493 FieldInt64 field = mFieldInt64Cache.get(sFieldInt64Supplier); 494 field.setValue(id, val); 495 mExtra.addPerfettoPointer(mCurrentContainer, field); 496 return this; 497 } 498 499 /** 500 * Adds a proto field with field id {@code id} and value {@code val}. 501 */ addField(long id, double val)502 public Builder addField(long id, double val) { 503 if (!mIsCategoryEnabled) { 504 return this; 505 } 506 if (DEBUG) { 507 checkContainer(); 508 } 509 FieldDouble field = mFieldDoubleCache.get(sFieldDoubleSupplier); 510 field.setValue(id, val); 511 mExtra.addPerfettoPointer(mCurrentContainer, field); 512 return this; 513 } 514 515 /** 516 * Adds a proto field with field id {@code id} and value {@code val}. 517 */ addField(long id, String val)518 public Builder addField(long id, String val) { 519 if (!mIsCategoryEnabled) { 520 return this; 521 } 522 if (DEBUG) { 523 checkContainer(); 524 } 525 FieldString field = mFieldStringCache.get(sFieldStringSupplier); 526 field.setValue(id, val); 527 mExtra.addPerfettoPointer(mCurrentContainer, field); 528 return this; 529 } 530 531 /** 532 * Begins a proto field. 533 * Fields can be added from this point and there must be a corresponding 534 * {@link endProto}. 535 * 536 * The proto field is a singleton and all proto fields get added inside the 537 * one {@link beginProto} and {@link endProto} within the {@link Builder}. 538 */ beginProto()539 public Builder beginProto() { 540 if (!mIsCategoryEnabled) { 541 return this; 542 } 543 if (DEBUG) { 544 checkParent(); 545 } 546 mProto.clearFields(); 547 mExtra.addPerfettoPointer(mProto); 548 return mBuilderCache.get(sBuilderSupplier).initInternal(this, mProto); 549 } 550 551 /** 552 * Ends a proto field. 553 */ endProto()554 public Builder endProto() { 555 if (!mIsCategoryEnabled) { 556 return this; 557 } 558 if (mParent == null || mCurrentContainer == null) { 559 throw new IllegalStateException("No proto to end"); 560 } 561 return mParent; 562 } 563 564 /** 565 * Begins a nested proto field with field id {@code id}. 566 * Fields can be added from this point and there must be a corresponding 567 * {@link endNested}. 568 */ beginNested(long id)569 public Builder beginNested(long id) { 570 if (!mIsCategoryEnabled) { 571 return this; 572 } 573 if (DEBUG) { 574 checkContainer(); 575 } 576 FieldNested field = mFieldNestedCache.get(sFieldNestedSupplier); 577 field.setId(id); 578 mExtra.addPerfettoPointer(mCurrentContainer, field); 579 return mBuilderCache.get(sBuilderSupplier).initInternal(this, field); 580 } 581 582 /** 583 * Ends a nested proto field. 584 */ endNested()585 public Builder endNested() { 586 if (!mIsCategoryEnabled) { 587 return this; 588 } 589 if (mParent == null || mCurrentContainer == null) { 590 throw new IllegalStateException("No nested field to end"); 591 } 592 return mParent; 593 } 594 595 initInternal(Builder parent, FieldContainer field)596 private Builder initInternal(Builder parent, FieldContainer field) { 597 mParent = parent; 598 mCurrentContainer = field; 599 mIsBuilt = false; 600 601 return this; 602 } 603 checkState()604 private void checkState() { 605 if (mIsBuilt) { 606 throw new IllegalStateException( 607 "This builder has already been used. Create a new builder for another event."); 608 } 609 } 610 checkParent()611 private void checkParent() { 612 checkState(); 613 if (!this.equals(mParent)) { 614 throw new IllegalStateException("Operation not supported for proto"); 615 } 616 } 617 checkContainer()618 private void checkContainer() { 619 checkState(); 620 if (mCurrentContainer == null) { 621 throw new IllegalStateException( 622 "Field operations must be within beginProto/endProto block"); 623 } 624 } 625 } 626 627 /** 628 * Start a {@link Builder} to build a {@link PerfettoTrackEventExtra}. 629 */ builder(boolean isCategoryEnabled)630 public static Builder builder(boolean isCategoryEnabled) { 631 if (isCategoryEnabled) { 632 return sTrackEventExtra.get().mBuilderCache.get(sBuilderSupplier) 633 .initInternal(null, null); 634 } 635 return NO_OP_BUILDER; 636 } 637 638 private final RingBuffer<NamedTrack> mNamedTrackCache = 639 new RingBuffer(DEFAULT_EXTRA_CACHE_SIZE); 640 private final RingBuffer<CounterTrack> mCounterTrackCache = 641 new RingBuffer(DEFAULT_EXTRA_CACHE_SIZE); 642 643 private final RingBuffer<ArgInt64> mArgInt64Cache = new RingBuffer(DEFAULT_EXTRA_CACHE_SIZE); 644 private final RingBuffer<ArgBool> mArgBoolCache = new RingBuffer(DEFAULT_EXTRA_CACHE_SIZE); 645 private final RingBuffer<ArgDouble> mArgDoubleCache = new RingBuffer(DEFAULT_EXTRA_CACHE_SIZE); 646 private final RingBuffer<ArgString> mArgStringCache = new RingBuffer(DEFAULT_EXTRA_CACHE_SIZE); 647 648 private final Pool<FieldInt64> mFieldInt64Cache = new Pool(DEFAULT_EXTRA_CACHE_SIZE); 649 private final Pool<FieldDouble> mFieldDoubleCache = new Pool(DEFAULT_EXTRA_CACHE_SIZE); 650 private final Pool<FieldString> mFieldStringCache = new Pool(DEFAULT_EXTRA_CACHE_SIZE); 651 private final Pool<FieldNested> mFieldNestedCache = new Pool(DEFAULT_EXTRA_CACHE_SIZE); 652 private final Pool<Builder> mBuilderCache = new Pool(DEFAULT_EXTRA_CACHE_SIZE); 653 654 private static final NativeAllocationRegistry sRegistry = 655 NativeAllocationRegistry.createMalloced( 656 PerfettoTrackEventExtra.class.getClassLoader(), native_delete()); 657 658 private final long mPtr; 659 private static final String TAG = "PerfettoTrackEventExtra"; 660 PerfettoTrackEventExtra()661 private PerfettoTrackEventExtra() { 662 mPtr = native_init(); 663 } 664 665 /** 666 * Returns the native pointer. 667 */ getPtr()668 public long getPtr() { 669 return mPtr; 670 } 671 672 /** 673 * Adds a pointer representing a track event parameter. 674 */ addPerfettoPointer(PerfettoPointer extra)675 public void addPerfettoPointer(PerfettoPointer extra) { 676 native_add_arg(mPtr, extra.getPtr()); 677 mPendingPointers.add(extra); 678 } 679 680 /** 681 * Adds a pointer representing a track event parameter to the {@code container}. 682 */ addPerfettoPointer(FieldContainer container, PerfettoPointer extra)683 public void addPerfettoPointer(FieldContainer container, PerfettoPointer extra) { 684 container.addField(extra); 685 mPendingPointers.add(extra); 686 } 687 688 /** 689 * Resets the track event extra. 690 */ reset()691 public void reset() { 692 native_clear_args(mPtr); 693 mPendingPointers.clear(); 694 } 695 getCounterInt64()696 private CounterInt64 getCounterInt64() { 697 if (mCounterInt64 == null) { 698 mCounterInt64 = new CounterInt64(); 699 } 700 return mCounterInt64; 701 } 702 getCounterDouble()703 private CounterDouble getCounterDouble() { 704 if (mCounterDouble == null) { 705 mCounterDouble = new CounterDouble(); 706 } 707 return mCounterDouble; 708 } 709 getProto()710 private Proto getProto() { 711 if (mProto == null) { 712 mProto = new Proto(); 713 } 714 return mProto; 715 } 716 getFlow()717 private Flow getFlow() { 718 if (mFlow == null) { 719 mFlow = new Flow(); 720 } 721 return mFlow; 722 } 723 getTerminatingFlow()724 private Flow getTerminatingFlow() { 725 if (mTerminatingFlow == null) { 726 mTerminatingFlow = new Flow(); 727 } 728 return mTerminatingFlow; 729 } 730 731 private static final class Flow implements PerfettoPointer { 732 private final long mPtr; 733 private final long mExtraPtr; 734 Flow()735 Flow() { 736 mPtr = native_init(); 737 mExtraPtr = native_get_extra_ptr(mPtr); 738 sRegistry.registerNativeAllocation(this, mPtr); 739 } 740 setProcessFlow(long type)741 public void setProcessFlow(long type) { 742 native_set_process_flow(mPtr, type); 743 } 744 setProcessTerminatingFlow(long id)745 public void setProcessTerminatingFlow(long id) { 746 native_set_process_terminating_flow(mPtr, id); 747 } 748 749 @Override getPtr()750 public long getPtr() { 751 return mExtraPtr; 752 } 753 754 @CriticalNative native_init()755 private static native long native_init(); 756 @CriticalNative native_delete()757 private static native long native_delete(); 758 @CriticalNative native_set_process_flow(long ptr, long type)759 private static native void native_set_process_flow(long ptr, long type); 760 @CriticalNative native_set_process_terminating_flow(long ptr, long id)761 private static native void native_set_process_terminating_flow(long ptr, long id); 762 @CriticalNative native_get_extra_ptr(long ptr)763 private static native long native_get_extra_ptr(long ptr); 764 } 765 766 private static class NamedTrack implements PerfettoPointer { 767 private static final NativeAllocationRegistry sRegistry = 768 NativeAllocationRegistry.createMalloced( 769 NamedTrack.class.getClassLoader(), native_delete()); 770 771 private final long mPtr; 772 private final long mExtraPtr; 773 private final String mName; 774 NamedTrack(String name, long parentUuid)775 NamedTrack(String name, long parentUuid) { 776 mPtr = native_init(sNamedTrackId.incrementAndGet(), name, parentUuid); 777 mExtraPtr = native_get_extra_ptr(mPtr); 778 mName = name; 779 sRegistry.registerNativeAllocation(this, mPtr); 780 } 781 782 @Override getPtr()783 public long getPtr() { 784 return mExtraPtr; 785 } 786 getName()787 public String getName() { 788 return mName; 789 } 790 791 @FastNative native_init(long id, String name, long parentUuid)792 private static native long native_init(long id, String name, long parentUuid); 793 @CriticalNative native_delete()794 private static native long native_delete(); 795 @CriticalNative native_get_extra_ptr(long ptr)796 private static native long native_get_extra_ptr(long ptr); 797 } 798 799 private static final class CounterTrack implements PerfettoPointer { 800 private static final NativeAllocationRegistry sRegistry = 801 NativeAllocationRegistry.createMalloced( 802 CounterTrack.class.getClassLoader(), native_delete()); 803 804 private final long mPtr; 805 private final long mExtraPtr; 806 private final String mName; 807 CounterTrack(String name, long parentUuid)808 CounterTrack(String name, long parentUuid) { 809 mPtr = native_init(name, parentUuid); 810 mExtraPtr = native_get_extra_ptr(mPtr); 811 mName = name; 812 sRegistry.registerNativeAllocation(this, mPtr); 813 } 814 815 @Override getPtr()816 public long getPtr() { 817 return mExtraPtr; 818 } 819 getName()820 public String getName() { 821 return mName; 822 } 823 824 @FastNative native_init(String name, long parentUuid)825 private static native long native_init(String name, long parentUuid); 826 @CriticalNative native_delete()827 private static native long native_delete(); 828 @CriticalNative native_get_extra_ptr(long ptr)829 private static native long native_get_extra_ptr(long ptr); 830 } 831 832 private static final class CounterInt64 implements PerfettoPointer { 833 private static final NativeAllocationRegistry sRegistry = 834 NativeAllocationRegistry.createMalloced( 835 CounterInt64.class.getClassLoader(), native_delete()); 836 837 private final long mPtr; 838 private final long mExtraPtr; 839 CounterInt64()840 CounterInt64() { 841 mPtr = native_init(); 842 mExtraPtr = native_get_extra_ptr(mPtr); 843 sRegistry.registerNativeAllocation(this, mPtr); 844 } 845 846 @Override getPtr()847 public long getPtr() { 848 return mExtraPtr; 849 } 850 setValue(long value)851 public void setValue(long value) { 852 native_set_value(mPtr, value); 853 } 854 855 @CriticalNative native_init()856 private static native long native_init(); 857 @CriticalNative native_delete()858 private static native long native_delete(); 859 @CriticalNative native_set_value(long ptr, long value)860 private static native void native_set_value(long ptr, long value); 861 @CriticalNative native_get_extra_ptr(long ptr)862 private static native long native_get_extra_ptr(long ptr); 863 } 864 865 private static final class CounterDouble implements PerfettoPointer { 866 private static final NativeAllocationRegistry sRegistry = 867 NativeAllocationRegistry.createMalloced( 868 CounterDouble.class.getClassLoader(), native_delete()); 869 870 private final long mPtr; 871 private final long mExtraPtr; 872 CounterDouble()873 CounterDouble() { 874 mPtr = native_init(); 875 mExtraPtr = native_get_extra_ptr(mPtr); 876 sRegistry.registerNativeAllocation(this, mPtr); 877 } 878 879 @Override getPtr()880 public long getPtr() { 881 return mExtraPtr; 882 } 883 setValue(double value)884 public void setValue(double value) { 885 native_set_value(mPtr, value); 886 } 887 888 @CriticalNative native_init()889 private static native long native_init(); 890 @CriticalNative native_delete()891 private static native long native_delete(); 892 @CriticalNative native_set_value(long ptr, double value)893 private static native void native_set_value(long ptr, double value); 894 @CriticalNative native_get_extra_ptr(long ptr)895 private static native long native_get_extra_ptr(long ptr); 896 } 897 898 private static final class ArgInt64 implements PerfettoPointer { 899 private static final NativeAllocationRegistry sRegistry = 900 NativeAllocationRegistry.createMalloced( 901 ArgInt64.class.getClassLoader(), native_delete()); 902 903 // Private pointer holding Perfetto object with metadata 904 private final long mPtr; 905 906 // Public pointer to Perfetto object itself 907 private final long mExtraPtr; 908 909 private final String mName; 910 ArgInt64(String name)911 ArgInt64(String name) { 912 mPtr = native_init(name); 913 mExtraPtr = native_get_extra_ptr(mPtr); 914 mName = name; 915 sRegistry.registerNativeAllocation(this, mPtr); 916 } 917 918 @Override getPtr()919 public long getPtr() { 920 return mExtraPtr; 921 } 922 getName()923 public String getName() { 924 return mName; 925 } 926 setValue(long val)927 public void setValue(long val) { 928 native_set_value(mPtr, val); 929 } 930 931 @FastNative native_init(String name)932 private static native long native_init(String name); 933 @CriticalNative native_delete()934 private static native long native_delete(); 935 @CriticalNative native_get_extra_ptr(long ptr)936 private static native long native_get_extra_ptr(long ptr); 937 @CriticalNative native_set_value(long ptr, long val)938 private static native void native_set_value(long ptr, long val); 939 } 940 941 private static final class ArgBool implements PerfettoPointer { 942 private static final NativeAllocationRegistry sRegistry = 943 NativeAllocationRegistry.createMalloced( 944 ArgBool.class.getClassLoader(), native_delete()); 945 946 // Private pointer holding Perfetto object with metadata 947 private final long mPtr; 948 949 // Public pointer to Perfetto object itself 950 private final long mExtraPtr; 951 952 private final String mName; 953 ArgBool(String name)954 ArgBool(String name) { 955 mPtr = native_init(name); 956 mExtraPtr = native_get_extra_ptr(mPtr); 957 mName = name; 958 sRegistry.registerNativeAllocation(this, mPtr); 959 } 960 961 @Override getPtr()962 public long getPtr() { 963 return mExtraPtr; 964 } 965 getName()966 public String getName() { 967 return mName; 968 } 969 setValue(boolean val)970 public void setValue(boolean val) { 971 native_set_value(mPtr, val); 972 } 973 974 @FastNative native_init(String name)975 private static native long native_init(String name); 976 @CriticalNative native_delete()977 private static native long native_delete(); 978 @CriticalNative native_get_extra_ptr(long ptr)979 private static native long native_get_extra_ptr(long ptr); 980 @CriticalNative native_set_value(long ptr, boolean val)981 private static native void native_set_value(long ptr, boolean val); 982 } 983 984 private static final class ArgDouble implements PerfettoPointer { 985 private static final NativeAllocationRegistry sRegistry = 986 NativeAllocationRegistry.createMalloced( 987 ArgDouble.class.getClassLoader(), native_delete()); 988 989 // Private pointer holding Perfetto object with metadata 990 private final long mPtr; 991 992 // Public pointer to Perfetto object itself 993 private final long mExtraPtr; 994 995 private final String mName; 996 ArgDouble(String name)997 ArgDouble(String name) { 998 mPtr = native_init(name); 999 mExtraPtr = native_get_extra_ptr(mPtr); 1000 mName = name; 1001 sRegistry.registerNativeAllocation(this, mPtr); 1002 } 1003 1004 @Override getPtr()1005 public long getPtr() { 1006 return mExtraPtr; 1007 } 1008 getName()1009 public String getName() { 1010 return mName; 1011 } 1012 setValue(double val)1013 public void setValue(double val) { 1014 native_set_value(mPtr, val); 1015 } 1016 1017 @FastNative native_init(String name)1018 private static native long native_init(String name); 1019 @CriticalNative native_delete()1020 private static native long native_delete(); 1021 @CriticalNative native_get_extra_ptr(long ptr)1022 private static native long native_get_extra_ptr(long ptr); 1023 @CriticalNative native_set_value(long ptr, double val)1024 private static native void native_set_value(long ptr, double val); 1025 } 1026 1027 private static final class ArgString implements PerfettoPointer { 1028 private static final NativeAllocationRegistry sRegistry = 1029 NativeAllocationRegistry.createMalloced( 1030 ArgString.class.getClassLoader(), native_delete()); 1031 1032 // Private pointer holding Perfetto object with metadata 1033 private final long mPtr; 1034 1035 // Public pointer to Perfetto object itself 1036 private final long mExtraPtr; 1037 1038 private final String mName; 1039 ArgString(String name)1040 ArgString(String name) { 1041 mPtr = native_init(name); 1042 mExtraPtr = native_get_extra_ptr(mPtr); 1043 mName = name; 1044 sRegistry.registerNativeAllocation(this, mPtr); 1045 } 1046 1047 @Override getPtr()1048 public long getPtr() { 1049 return mExtraPtr; 1050 } 1051 getName()1052 public String getName() { 1053 return mName; 1054 } 1055 setValue(String val)1056 public void setValue(String val) { 1057 native_set_value(mPtr, val); 1058 } 1059 1060 @FastNative native_init(String name)1061 private static native long native_init(String name); 1062 @CriticalNative native_delete()1063 private static native long native_delete(); 1064 @CriticalNative native_get_extra_ptr(long ptr)1065 private static native long native_get_extra_ptr(long ptr); 1066 @FastNative native_set_value(long ptr, String val)1067 private static native void native_set_value(long ptr, String val); 1068 } 1069 1070 private static final class Proto implements PerfettoPointer, FieldContainer { 1071 private static final NativeAllocationRegistry sRegistry = 1072 NativeAllocationRegistry.createMalloced( 1073 Proto.class.getClassLoader(), native_delete()); 1074 1075 // Private pointer holding Perfetto object with metadata 1076 private final long mPtr; 1077 1078 // Public pointer to Perfetto object itself 1079 private final long mExtraPtr; 1080 Proto()1081 Proto() { 1082 mPtr = native_init(); 1083 mExtraPtr = native_get_extra_ptr(mPtr); 1084 sRegistry.registerNativeAllocation(this, mPtr); 1085 } 1086 1087 @Override getPtr()1088 public long getPtr() { 1089 return mExtraPtr; 1090 } 1091 1092 @Override addField(PerfettoPointer field)1093 public void addField(PerfettoPointer field) { 1094 native_add_field(mPtr, field.getPtr()); 1095 } 1096 clearFields()1097 public void clearFields() { 1098 native_clear_fields(mPtr); 1099 } 1100 1101 @CriticalNative native_init()1102 private static native long native_init(); 1103 @CriticalNative native_delete()1104 private static native long native_delete(); 1105 @CriticalNative native_get_extra_ptr(long ptr)1106 private static native long native_get_extra_ptr(long ptr); 1107 @CriticalNative native_add_field(long ptr, long extraPtr)1108 private static native void native_add_field(long ptr, long extraPtr); 1109 @CriticalNative native_clear_fields(long ptr)1110 private static native void native_clear_fields(long ptr); 1111 } 1112 1113 private static final class FieldInt64 implements PerfettoPointer { 1114 private static final NativeAllocationRegistry sRegistry = 1115 NativeAllocationRegistry.createMalloced( 1116 FieldInt64.class.getClassLoader(), native_delete()); 1117 1118 // Private pointer holding Perfetto object with metadata 1119 private final long mPtr; 1120 1121 // Public pointer to Perfetto object itself 1122 private final long mFieldPtr; 1123 FieldInt64()1124 FieldInt64() { 1125 mPtr = native_init(); 1126 mFieldPtr = native_get_extra_ptr(mPtr); 1127 sRegistry.registerNativeAllocation(this, mPtr); 1128 } 1129 1130 @Override getPtr()1131 public long getPtr() { 1132 return mFieldPtr; 1133 } 1134 setValue(long id, long val)1135 public void setValue(long id, long val) { 1136 native_set_value(mPtr, id, val); 1137 } 1138 1139 @CriticalNative native_init()1140 private static native long native_init(); 1141 @CriticalNative native_delete()1142 private static native long native_delete(); 1143 @CriticalNative native_get_extra_ptr(long ptr)1144 private static native long native_get_extra_ptr(long ptr); 1145 @CriticalNative native_set_value(long ptr, long id, long val)1146 private static native void native_set_value(long ptr, long id, long val); 1147 } 1148 1149 private static final class FieldDouble implements PerfettoPointer { 1150 private static final NativeAllocationRegistry sRegistry = 1151 NativeAllocationRegistry.createMalloced( 1152 FieldDouble.class.getClassLoader(), native_delete()); 1153 1154 // Private pointer holding Perfetto object with metadata 1155 private final long mPtr; 1156 1157 // Public pointer to Perfetto object itself 1158 private final long mFieldPtr; 1159 FieldDouble()1160 FieldDouble() { 1161 mPtr = native_init(); 1162 mFieldPtr = native_get_extra_ptr(mPtr); 1163 sRegistry.registerNativeAllocation(this, mPtr); 1164 } 1165 1166 @Override getPtr()1167 public long getPtr() { 1168 return mFieldPtr; 1169 } 1170 setValue(long id, double val)1171 public void setValue(long id, double val) { 1172 native_set_value(mPtr, id, val); 1173 } 1174 1175 @CriticalNative native_init()1176 private static native long native_init(); 1177 @CriticalNative native_delete()1178 private static native long native_delete(); 1179 @CriticalNative native_get_extra_ptr(long ptr)1180 private static native long native_get_extra_ptr(long ptr); 1181 @CriticalNative native_set_value(long ptr, long id, double val)1182 private static native void native_set_value(long ptr, long id, double val); 1183 } 1184 1185 private static final class FieldString implements PerfettoPointer { 1186 private static final NativeAllocationRegistry sRegistry = 1187 NativeAllocationRegistry.createMalloced( 1188 FieldString.class.getClassLoader(), native_delete()); 1189 1190 // Private pointer holding Perfetto object with metadata 1191 private final long mPtr; 1192 1193 // Public pointer to Perfetto object itself 1194 private final long mFieldPtr; 1195 FieldString()1196 FieldString() { 1197 mPtr = native_init(); 1198 mFieldPtr = native_get_extra_ptr(mPtr); 1199 sRegistry.registerNativeAllocation(this, mPtr); 1200 } 1201 1202 @Override getPtr()1203 public long getPtr() { 1204 return mFieldPtr; 1205 } 1206 setValue(long id, String val)1207 public void setValue(long id, String val) { 1208 native_set_value(mPtr, id, val); 1209 } 1210 1211 @CriticalNative native_init()1212 private static native long native_init(); 1213 @CriticalNative native_delete()1214 private static native long native_delete(); 1215 @CriticalNative native_get_extra_ptr(long ptr)1216 private static native long native_get_extra_ptr(long ptr); 1217 @FastNative native_set_value(long ptr, long id, String val)1218 private static native void native_set_value(long ptr, long id, String val); 1219 } 1220 1221 private static final class FieldNested implements PerfettoPointer, FieldContainer { 1222 private static final NativeAllocationRegistry sRegistry = 1223 NativeAllocationRegistry.createMalloced( 1224 FieldNested.class.getClassLoader(), native_delete()); 1225 1226 // Private pointer holding Perfetto object with metadata 1227 private final long mPtr; 1228 1229 // Public pointer to Perfetto object itself 1230 private final long mFieldPtr; 1231 FieldNested()1232 FieldNested() { 1233 mPtr = native_init(); 1234 mFieldPtr = native_get_extra_ptr(mPtr); 1235 sRegistry.registerNativeAllocation(this, mPtr); 1236 } 1237 1238 @Override getPtr()1239 public long getPtr() { 1240 return mFieldPtr; 1241 } 1242 1243 @Override addField(PerfettoPointer field)1244 public void addField(PerfettoPointer field) { 1245 native_add_field(mPtr, field.getPtr()); 1246 } 1247 setId(long id)1248 public void setId(long id) { 1249 native_set_id(mPtr, id); 1250 } 1251 1252 @CriticalNative native_init()1253 private static native long native_init(); 1254 @CriticalNative native_delete()1255 private static native long native_delete(); 1256 @CriticalNative native_get_extra_ptr(long ptr)1257 private static native long native_get_extra_ptr(long ptr); 1258 @CriticalNative native_add_field(long ptr, long extraPtr)1259 private static native void native_add_field(long ptr, long extraPtr); 1260 @CriticalNative native_set_id(long ptr, long id)1261 private static native void native_set_id(long ptr, long id); 1262 } 1263 1264 @CriticalNative native_init()1265 private static native long native_init(); 1266 @CriticalNative native_delete()1267 private static native long native_delete(); 1268 @CriticalNative native_add_arg(long ptr, long extraPtr)1269 private static native void native_add_arg(long ptr, long extraPtr); 1270 @CriticalNative native_clear_args(long ptr)1271 private static native void native_clear_args(long ptr); 1272 @FastNative native_emit(int type, long tag, String name, long ptr)1273 private static native void native_emit(int type, long tag, String name, long ptr); 1274 } 1275