xref: /aosp_15_r20/external/leakcanary2/shark-android/src/main/java/shark/AndroidExtensions.kt (revision d9e8da70d8c9df9a41d7848ae506fb3115cae6e6)
1 package shark
2 
3 import shark.HeapObject.HeapInstance
4 
5 /**
6  * The system identity hash code, or null if it couldn't be found.
7  *
8  * Based on the Object.identityHashCode implementation in AOSP.
9  *
10  * Backing field shadow$_monitor_ was added in API 24.
11  * https://cs.android.com/android/_/android/platform/libcore/+
12  * /de626ec8a109ea18283d96c720cc57e2f32f67fa:ojluni/src/main/java/java/lang/Object.java;
13  * dlc=ba7cc9f5357c323a1006119a20ce025fd4c57fd2
14  */
15 val HeapInstance.identityHashCode: Int?
16   get() {
17     // Top 2 bits.
18     val lockWordStateMask = -0x40000000
19     // Top 2 bits are value 2 (kStateHash).
20     val lockWordStateHash = -0x80000000
21     // Low 28 bits.
22     val lockWordHashMask = 0x0FFFFFFF
23     val lockWord = this["java.lang.Object", "shadow\$_monitor_"]?.value?.asInt
24     return if (lockWord != null && lockWord and lockWordStateMask == lockWordStateHash) {
25       lockWord and lockWordHashMask
26     } else null
27   }
28 
29 /**
30  * The system identity hashCode represented as hex, or null if it couldn't be found.
31  * This is the string identifier you see when calling Object.toString() at runtime on a class that
32  * does not override its hashCode() method, e.g. com.example.MyThing@6bd57cf
33  */
34 val HeapInstance.hexIdentityHashCode: String?
35   get() {
36     val hashCode = identityHashCode ?: return null
37     return Integer.toHexString(hashCode)
38   }
39