1 /*
2  * Copyright (C) 2015 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 import java.lang.ref.PhantomReference;
18 import java.lang.ref.ReferenceQueue;
19 import java.lang.ref.SoftReference;
20 import java.lang.ref.WeakReference;
21 import libcore.util.NativeAllocationRegistry;
22 import android.graphics.Bitmap;
23 
24 // We take a heap dump that includes a single instance of this
25 // DumpedStuff class. Objects stored as fields in this class can be easily
26 // found in the hprof dump by searching for the instance of the DumpedStuff
27 // class and reading the desired field.
28 public class DumpedStuff extends SuperDumpedStuff {
allocateObjectAtKnownSite()29   private void allocateObjectAtKnownSite() {
30     objectAllocatedAtKnownSite = new Object();
31     allocateObjectAtKnownSubSite();
32     allocateObjectAtObfSuperSite();
33     allocateObjectAtUnObfSuperSite();
34     allocateObjectAtOverriddenSite();
35   }
36 
allocateObjectAtKnownSubSite()37   private void allocateObjectAtKnownSubSite() {
38     objectAllocatedAtKnownSubSite = new Object();
39   }
40 
allocateObjectAtOverriddenSite()41   public void allocateObjectAtOverriddenSite() {
42     objectAllocatedAtOverriddenSite = new Object();
43   }
44 
DumpedStuff(boolean baseline)45   DumpedStuff(boolean baseline) {
46     allocateObjectAtKnownSite();
47 
48     int n = baseline ? 400000 : 1000000;
49     bigArray = new byte[n];
50     for (int i = 0; i < n; i++) {
51       bigArray[i] = (byte)((i * i) & 0xFF);
52     }
53 
54     // 0x12345, 50000, and 0xABCDABCD are arbitrary values.
55     NativeAllocationRegistry registry = new NativeAllocationRegistry(
56         Main.class.getClassLoader(), 0x12345, 50000);
57     registry.registerNativeAllocation(anObject, 0xABCDABCD);
58 
59     {
60       Object object = new Object();
61       aLongStrongPathToSamplePathObject = new Reference(new Reference(new Reference(object)));
62       aShortWeakPathToSamplePathObject = new WeakReference(new Reference(object));
63     }
64 
65     addedObject = baseline ? null : new AddedObject();
66     removedObject = baseline ? new RemovedObject() : null;
67     modifiedObject = new ModifiedObject();
68     modifiedObject.value = baseline ? 5 : 8;
69     modifiedObject.modifiedRefField = baseline ? "A1" : "A2";
70     modifiedObject.unmodifiedRefField = "B";
71     modifiedStaticField = baseline ? "C1" : "C2";
72     modifiedArray = baseline ? new int[]{0, 1, 2, 3} : new int[]{3, 1, 2, 0};
73 
74     // Deep matching dominator trees shouldn't smash the stack when we try
75     // to diff them. Make some deep dominator trees to help test it.
76     for (int i = 0; i < 10000; i++) {
77       StackSmasher smasher = new StackSmasher();
78       smasher.child = stackSmasher;
79       stackSmasher = smasher;
80 
81       if (!baseline) {
82         smasher = new StackSmasher();
83         smasher.child = stackSmasherAdded;
84         stackSmasherAdded = smasher;
85       }
86     }
87 
88     gcPathArray[2].right.left = gcPathArray[2].left.right;
89 
90     bitmapOne = new Bitmap(100, 200, 0xDEADBEEF, bigArray);
91     bitmapTwo = new Bitmap(100, 200, 0xBEEFDEAD, bigArray);
92   }
93 
94   public static class ObjectTree {
95     public ObjectTree left;
96     public ObjectTree right;
97 
ObjectTree(ObjectTree left, ObjectTree right)98     public ObjectTree(ObjectTree left, ObjectTree right) {
99       this.left = left;
100       this.right = right;
101     }
102   }
103 
104   public static class AddedObject {
105   }
106 
107   public static class RemovedObject {
108   }
109 
110   public static class UnchangedObject {
111   }
112 
113   public static class ModifiedObject {
114     public int value;
115     public String modifiedRefField;
116     public String unmodifiedRefField;
117   }
118 
119   public static class StackSmasher {
120     public StackSmasher child;
121   }
122 
123   public static class Reference {
124     public Object referent;
125 
Reference(Object referent)126     public Reference(Object referent) {
127       this.referent = referent;
128     }
129   }
130 
131   public interface IDumpedManager {
132     public static class Stub extends android.os.Binder implements IDumpedManager {
133       private static final java.lang.String DESCRIPTOR = "DumpedStuff$IDumpedManager";
Stub()134       public Stub() {
135         super(DESCRIPTOR);
136       }
137       public static class Proxy implements IDumpedManager {
138         android.os.IBinder mRemote;
Proxy(android.os.IBinder binderProxy)139         Proxy(android.os.IBinder binderProxy) {
140           mRemote = binderProxy;
141         }
142       }
143     }
144   }
145 
146   public interface IBinderInterfaceImpostor {
147     public static class Stub {
148       public static class Proxy implements IBinderInterfaceImpostor {
149         android.os.IBinder mFakeRemote = new android.os.BinderProxy();
Proxy(android.os.IBinder binderProxy)150         Proxy(android.os.IBinder binderProxy) {
151           mFakeRemote = binderProxy;
152         }
153       }
154     }
155   }
156 
157   private static class BinderProxyCarrier {
158     android.os.IBinder mRemote;
BinderProxyCarrier(android.os.IBinder binderProxy)159     BinderProxyCarrier(android.os.IBinder binderProxy) {
160       mRemote = binderProxy;
161     }
162   }
163 
164   private static class BinderService extends IDumpedManager.Stub {
165     // Intentionally empty
166   };
167 
168   private static class FakeBinderService extends IBinderInterfaceImpostor.Stub {
169     // Intentionally empty
170   };
171 
172   public String basicString = "hello, world";
173   public String nonAscii = "Sigma (Ʃ) is not ASCII";
174   public String embeddedZero = "embedded\0...";  // Non-ASCII for string compression purposes.
175   public char[] charArray = "char thing".toCharArray();
176   public String nullString = null;
177   public Object anObject = new Object();
178   public Reference aReference = new Reference(anObject);
179   public ReferenceQueue<Object> referenceQueue = new ReferenceQueue<Object>();
180   public PhantomReference aPhantomReference = new PhantomReference(anObject, referenceQueue);
181   public WeakReference aWeakReference = new WeakReference(anObject, referenceQueue);
182   public WeakReference aNullReferentReference = new WeakReference(null, referenceQueue);
183   public SoftReference aSoftReference = new SoftReference(new Object());
184   public Reference reachabilityReferenceChain;
185   public byte[] bigArray;
186   public Bitmap bitmapOne = null;
187   public Bitmap bitmapTwo = null;
188   public ObjectTree[] gcPathArray = new ObjectTree[]{null, null,
189     new ObjectTree(
190         new ObjectTree(null, new ObjectTree(null, null)),
191         new ObjectTree(null, null)),
192     null};
193   public Reference aLongStrongPathToSamplePathObject;
194   public WeakReference aShortWeakPathToSamplePathObject;
195   public WeakReference aWeakRefToGcRoot = new WeakReference(Main.class);
196   public SoftReference aSoftChain = new SoftReference(new Reference(new Reference(new Object())));
197   public Object[] basicStringRef;
198   public AddedObject addedObject;
199   public UnchangedObject unchangedObject = new UnchangedObject();
200   public RemovedObject removedObject;
201   public ModifiedObject modifiedObject;
202   public StackSmasher stackSmasher;
203   public StackSmasher stackSmasherAdded;
204   public static String modifiedStaticField;
205   public int[] modifiedArray;
206   public Object objectAllocatedAtKnownSite;
207   public Object objectAllocatedAtKnownSubSite;
208   public android.os.IBinder correctBinderProxy = new android.os.BinderProxy();
209   public android.os.IBinder imposedBinderProxy = new android.os.BinderProxy();
210   public android.os.IBinder carriedBinderProxy = new android.os.BinderProxy();
211   Object correctBinderProxyObject = new IDumpedManager.Stub.Proxy(correctBinderProxy);
212   Object impostorBinderProxyObject = new IBinderInterfaceImpostor.Stub.Proxy(imposedBinderProxy);
213   Object carrierBinderProxyObject = new BinderProxyCarrier(carriedBinderProxy);
214 
215   Object binderService = new BinderService();
216   Object fakeBinderService = new FakeBinderService();
217   Object binderToken = new android.os.Binder();
218   Object namedBinderToken = new android.os.Binder("awesomeToken");
219 
220   // Allocate those objects that we need to not be GC'd before taking the heap
221   // dump.
shouldNotGc()222   public void shouldNotGc() {
223     reachabilityReferenceChain = new Reference(
224         new SoftReference(
225         new Reference(
226         new WeakReference(
227         new SoftReference(
228         new PhantomReference(new Object(), referenceQueue))))));
229   }
230 }
231