-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathClientData.java
659 lines (567 loc) · 20.4 KB
/
ClientData.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
/*
* Copyright (C) 2007 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.ddmlib;
import com.android.ddmlib.HeapSegment.HeapSegmentElement;
import java.nio.BufferUnderflowException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.TreeSet;
/**
* Contains the data of a {@link Client}.
*/
public class ClientData {
/* This is a place to stash data associated with a Client, such as thread
* states or heap data. ClientData maps 1:1 to Client, but it's a little
* cleaner if we separate the data out.
*
* Message handlers are welcome to stash arbitrary data here.
*
* IMPORTANT: The data here is written by HandleFoo methods and read by
* FooPanel methods, which run in different threads. All non-trivial
* access should be synchronized against the ClientData object.
*/
/** Temporary name of VM to be ignored. */
private final static String PRE_INITIALIZED = "<pre-initialized>"; //$NON-NLS-1$
public static enum DebuggerStatus {
/** Debugger connection status: not waiting on one, not connected to one, but accepting
* new connections. This is the default value. */
DEFAULT,
/**
* Debugger connection status: the application's VM is paused, waiting for a debugger to
* connect to it before resuming. */
WAITING,
/** Debugger connection status : Debugger is connected */
ATTACHED,
/** Debugger connection status: The listening port for debugger connection failed to listen.
* No debugger will be able to connect. */
ERROR;
}
public static enum AllocationTrackingStatus {
/**
* Allocation tracking status: unknown.
* <p/>This happens right after a {@link Client} is discovered
* by the {@link AndroidDebugBridge}, and before the {@link Client} answered the query
* regarding its allocation tracking status.
* @see Client#requestAllocationStatus()
*/
UNKNOWN,
/** Allocation tracking status: the {@link Client} is not tracking allocations. */
OFF,
/** Allocation tracking status: the {@link Client} is tracking allocations. */
ON;
}
public static enum MethodProfilingStatus {
/**
* Method profiling status: unknown.
* <p/>This happens right after a {@link Client} is discovered
* by the {@link AndroidDebugBridge}, and before the {@link Client} answered the query
* regarding its method profiling status.
* @see Client#requestMethodProfilingStatus()
*/
UNKNOWN,
/** Method profiling status: the {@link Client} is not profiling method calls. */
OFF,
/** Method profiling status: the {@link Client} is profiling method calls. */
ON;
}
/**
* Name of the value representing the max size of the heap, in the {@link Map} returned by
* {@link #getVmHeapInfo(int)}
*/
public final static String HEAP_MAX_SIZE_BYTES = "maxSizeInBytes"; // $NON-NLS-1$
/**
* Name of the value representing the size of the heap, in the {@link Map} returned by
* {@link #getVmHeapInfo(int)}
*/
public final static String HEAP_SIZE_BYTES = "sizeInBytes"; // $NON-NLS-1$
/**
* Name of the value representing the number of allocated bytes of the heap, in the
* {@link Map} returned by {@link #getVmHeapInfo(int)}
*/
public final static String HEAP_BYTES_ALLOCATED = "bytesAllocated"; // $NON-NLS-1$
/**
* Name of the value representing the number of objects in the heap, in the {@link Map}
* returned by {@link #getVmHeapInfo(int)}
*/
public final static String HEAP_OBJECTS_ALLOCATED = "objectsAllocated"; // $NON-NLS-1$
/**
* String for feature enabling starting/stopping method profiling
* @see #hasFeature(String)
*/
public final static String FEATURE_PROFILING = "method-trace-profiling"; // $NON-NLS-1$
/**
* String for feature allowing to dump hprof files
* @see #hasFeature(String)
*/
public final static String FEATURE_HPROF = "hprof-heap-dump"; // $NON-NLS-1$
private static IHprofDumpHandler sHprofDumpHandler;
private static IMethodProfilingHandler sMethodProfilingHandler;
// is this a DDM-aware client?
private boolean mIsDdmAware;
// the client's process ID
private final int mPid;
// Java VM identification string
private String mVmIdentifier;
// client's self-description
private String mClientDescription;
// how interested are we in a debugger?
private DebuggerStatus mDebuggerInterest;
// List of supported features by the client.
private final HashSet<String> mFeatures = new HashSet<String>();
// Thread tracking (THCR, THDE).
private TreeMap<Integer,ThreadInfo> mThreadMap;
/** VM Heap data */
private final HeapData mHeapData = new HeapData();
/** Native Heap data */
private final HeapData mNativeHeapData = new HeapData();
private HashMap<Integer, HashMap<String, Long>> mHeapInfoMap =
new HashMap<Integer, HashMap<String, Long>>();
/** library map info. Stored here since the backtrace data
* is computed on a need to display basis.
*/
private ArrayList<NativeLibraryMapInfo> mNativeLibMapInfo =
new ArrayList<NativeLibraryMapInfo>();
/** Native Alloc info list */
private ArrayList<NativeAllocationInfo> mNativeAllocationList =
new ArrayList<NativeAllocationInfo>();
private int mNativeTotalMemory;
private AllocationInfo[] mAllocations;
private AllocationTrackingStatus mAllocationStatus = AllocationTrackingStatus.UNKNOWN;
private String mPendingHprofDump;
private MethodProfilingStatus mProfilingStatus = MethodProfilingStatus.UNKNOWN;
private String mPendingMethodProfiling;
/**
* Heap Information.
* <p/>The heap is composed of several {@link HeapSegment} objects.
* <p/>A call to {@link #isHeapDataComplete()} will indicate if the segments (available through
* {@link #getHeapSegments()}) represent the full heap.
*/
public static class HeapData {
private TreeSet<HeapSegment> mHeapSegments = new TreeSet<HeapSegment>();
private boolean mHeapDataComplete = false;
private byte[] mProcessedHeapData;
private Map<Integer, ArrayList<HeapSegmentElement>> mProcessedHeapMap;
/**
* Abandon the current list of heap segments.
*/
public synchronized void clearHeapData() {
/* Abandon the old segments instead of just calling .clear().
* This lets the user hold onto the old set if it wants to.
*/
mHeapSegments = new TreeSet<HeapSegment>();
mHeapDataComplete = false;
}
/**
* Add raw HPSG chunk data to the list of heap segments.
*
* @param data The raw data from an HPSG chunk.
*/
synchronized void addHeapData(ByteBuffer data) {
HeapSegment hs;
if (mHeapDataComplete) {
clearHeapData();
}
try {
hs = new HeapSegment(data);
} catch (BufferUnderflowException e) {
System.err.println("Discarding short HPSG data (length " + data.limit() + ")");
return;
}
mHeapSegments.add(hs);
}
/**
* Called when all heap data has arrived.
*/
synchronized void sealHeapData() {
mHeapDataComplete = true;
}
/**
* Returns whether the heap data has been sealed.
*/
public boolean isHeapDataComplete() {
return mHeapDataComplete;
}
/**
* Get the collected heap data, if sealed.
*
* @return The list of heap segments if the heap data has been sealed, or null if it hasn't.
*/
public Collection<HeapSegment> getHeapSegments() {
if (isHeapDataComplete()) {
return mHeapSegments;
}
return null;
}
/**
* Sets the processed heap data.
*
* @param heapData The new heap data (can be null)
*/
public void setProcessedHeapData(byte[] heapData) {
mProcessedHeapData = heapData;
}
/**
* Get the processed heap data, if present.
*
* @return the processed heap data, or null.
*/
public byte[] getProcessedHeapData() {
return mProcessedHeapData;
}
public void setProcessedHeapMap(Map<Integer, ArrayList<HeapSegmentElement>> heapMap) {
mProcessedHeapMap = heapMap;
}
public Map<Integer, ArrayList<HeapSegmentElement>> getProcessedHeapMap() {
return mProcessedHeapMap;
}
}
/**
* Handlers able to act on HPROF dumps.
*/
public interface IHprofDumpHandler {
/**
* Called when a HPROF dump succeeded.
* @param remoteFilePath the device-side path of the HPROF file.
* @param client the client for which the HPROF file was.
*/
void onSuccess(String remoteFilePath, Client client);
/**
* Called when the HPROF dump failed.
* @param client the client for which the HPROF file was.
*/
void onFailure(Client client);
}
/**
* Handlers able to act on Method profiling info
*/
public interface IMethodProfilingHandler {
/**
* Called when a method tracing was successful.
* @param remoteFilePath the device-side path of the trace file.
* @param client the client that was profiled.
*/
void onSuccess(String remoteFilePath, Client client);
/**
* Called when method tracing failed.
* @param client the client that was profiled.
*/
void onFailure(Client client);
}
/**
* Sets the handler to receive notifications when an HPROF dump succeeded or failed.
*/
public static void setHprofDumpHandler(IHprofDumpHandler handler) {
sHprofDumpHandler = handler;
}
static IHprofDumpHandler getHprofDumpHandler() {
return sHprofDumpHandler;
}
/**
* Sets the handler to receive notifications when an HPROF dump succeeded or failed.
*/
public static void setMethodProfilingHandler(IMethodProfilingHandler handler) {
sMethodProfilingHandler = handler;
}
static IMethodProfilingHandler getMethodProfilingHandler() {
return sMethodProfilingHandler;
}
/**
* Generic constructor.
*/
ClientData(int pid) {
mPid = pid;
mDebuggerInterest = DebuggerStatus.DEFAULT;
mThreadMap = new TreeMap<Integer,ThreadInfo>();
}
/**
* Returns whether the process is DDM-aware.
*/
public boolean isDdmAware() {
return mIsDdmAware;
}
/**
* Sets DDM-aware status.
*/
void isDdmAware(boolean aware) {
mIsDdmAware = aware;
}
/**
* Returns the process ID.
*/
public int getPid() {
return mPid;
}
/**
* Returns the Client's VM identifier.
*/
public String getVmIdentifier() {
return mVmIdentifier;
}
/**
* Sets VM identifier.
*/
void setVmIdentifier(String ident) {
mVmIdentifier = ident;
}
/**
* Returns the client description.
* <p/>This is generally the name of the package defined in the
* <code>AndroidManifest.xml</code>.
*
* @return the client description or <code>null</code> if not the description was not yet
* sent by the client.
*/
public String getClientDescription() {
return mClientDescription;
}
/**
* Sets client description.
*
* There may be a race between HELO and APNM. Rather than try
* to enforce ordering on the device, we just don't allow an empty
* name to replace a specified one.
*/
void setClientDescription(String description) {
if (mClientDescription == null && description.length() > 0) {
/*
* The application VM is first named <pre-initialized> before being assigned
* its real name.
* Depending on the timing, we can get an APNM chunk setting this name before
* another one setting the final actual name. So if we get a SetClientDescription
* with this value we ignore it.
*/
if (PRE_INITIALIZED.equals(description) == false) {
mClientDescription = description;
}
}
}
/**
* Returns the debugger connection status.
*/
public DebuggerStatus getDebuggerConnectionStatus() {
return mDebuggerInterest;
}
/**
* Sets debugger connection status.
*/
void setDebuggerConnectionStatus(DebuggerStatus status) {
mDebuggerInterest = status;
}
/**
* Sets the current heap info values for the specified heap.
*
* @param heapId The heap whose info to update
* @param sizeInBytes The size of the heap, in bytes
* @param bytesAllocated The number of bytes currently allocated in the heap
* @param objectsAllocated The number of objects currently allocated in
* the heap
*/
// TODO: keep track of timestamp, reason
synchronized void setHeapInfo(int heapId, long maxSizeInBytes,
long sizeInBytes, long bytesAllocated, long objectsAllocated) {
HashMap<String, Long> heapInfo = new HashMap<String, Long>();
heapInfo.put(HEAP_MAX_SIZE_BYTES, maxSizeInBytes);
heapInfo.put(HEAP_SIZE_BYTES, sizeInBytes);
heapInfo.put(HEAP_BYTES_ALLOCATED, bytesAllocated);
heapInfo.put(HEAP_OBJECTS_ALLOCATED, objectsAllocated);
mHeapInfoMap.put(heapId, heapInfo);
}
/**
* Returns the {@link HeapData} object for the VM.
*/
public HeapData getVmHeapData() {
return mHeapData;
}
/**
* Returns the {@link HeapData} object for the native code.
*/
HeapData getNativeHeapData() {
return mNativeHeapData;
}
/**
* Returns an iterator over the list of known VM heap ids.
* <p/>
* The caller must synchronize on the {@link ClientData} object while iterating.
*
* @return an iterator over the list of heap ids
*/
public synchronized Iterator<Integer> getVmHeapIds() {
return mHeapInfoMap.keySet().iterator();
}
/**
* Returns the most-recent info values for the specified VM heap.
*
* @param heapId The heap whose info should be returned
* @return a map containing the info values for the specified heap.
* Returns <code>null</code> if the heap ID is unknown.
*/
public synchronized Map<String, Long> getVmHeapInfo(int heapId) {
return mHeapInfoMap.get(heapId);
}
/**
* Adds a new thread to the list.
*/
synchronized void addThread(int threadId, String threadName) {
ThreadInfo attr = new ThreadInfo(threadId, threadName);
mThreadMap.put(threadId, attr);
}
/**
* Removes a thread from the list.
*/
synchronized void removeThread(int threadId) {
mThreadMap.remove(threadId);
}
/**
* Returns the list of threads as {@link ThreadInfo} objects.
* <p/>The list is empty until a thread update was requested with
* {@link Client#requestThreadUpdate()}.
*/
public synchronized ThreadInfo[] getThreads() {
Collection<ThreadInfo> threads = mThreadMap.values();
return threads.toArray(new ThreadInfo[threads.size()]);
}
/**
* Returns the {@link ThreadInfo} by thread id.
*/
synchronized ThreadInfo getThread(int threadId) {
return mThreadMap.get(threadId);
}
synchronized void clearThreads() {
mThreadMap.clear();
}
/**
* Returns the list of {@link NativeAllocationInfo}.
* @see Client#requestNativeHeapInformation()
*/
public synchronized List<NativeAllocationInfo> getNativeAllocationList() {
return Collections.unmodifiableList(mNativeAllocationList);
}
/**
* adds a new {@link NativeAllocationInfo} to the {@link Client}
* @param allocInfo The {@link NativeAllocationInfo} to add.
*/
synchronized void addNativeAllocation(NativeAllocationInfo allocInfo) {
mNativeAllocationList.add(allocInfo);
}
/**
* Clear the current malloc info.
*/
synchronized void clearNativeAllocationInfo() {
mNativeAllocationList.clear();
}
/**
* Returns the total native memory.
* @see Client#requestNativeHeapInformation()
*/
public synchronized int getTotalNativeMemory() {
return mNativeTotalMemory;
}
synchronized void setTotalNativeMemory(int totalMemory) {
mNativeTotalMemory = totalMemory;
}
synchronized void addNativeLibraryMapInfo(long startAddr, long endAddr, String library) {
mNativeLibMapInfo.add(new NativeLibraryMapInfo(startAddr, endAddr, library));
}
/**
* Returns an {@link Iterator} on {@link NativeLibraryMapInfo} objects.
* <p/>
* The caller must synchronize on the {@link ClientData} object while iterating.
*/
public synchronized Iterator<NativeLibraryMapInfo> getNativeLibraryMapInfo() {
return mNativeLibMapInfo.iterator();
}
synchronized void setAllocationStatus(AllocationTrackingStatus status) {
mAllocationStatus = status;
}
/**
* Returns the allocation tracking status.
* @see Client#requestAllocationStatus()
*/
public synchronized AllocationTrackingStatus getAllocationStatus() {
return mAllocationStatus;
}
synchronized void setAllocations(AllocationInfo[] allocs) {
mAllocations = allocs;
}
/**
* Returns the list of tracked allocations.
* @see Client#requestAllocationDetails()
*/
public synchronized AllocationInfo[] getAllocations() {
return mAllocations;
}
void addFeature(String feature) {
mFeatures.add(feature);
}
/**
* Returns true if the {@link Client} supports the given <var>feature</var>
* @param feature The feature to test.
* @return true if the feature is supported
*
* @see ClientData#FEATURE_PROFILING
* @see ClientData#FEATURE_HPROF
*/
public boolean hasFeature(String feature) {
return mFeatures.contains(feature);
}
/**
* Sets the device-side path to the hprof file being written
* @param pendingHprofDump the file to the hprof file
*/
void setPendingHprofDump(String pendingHprofDump) {
mPendingHprofDump = pendingHprofDump;
}
/**
* Returns the path to the device-side hprof file being written.
*/
String getPendingHprofDump() {
return mPendingHprofDump;
}
public boolean hasPendingHprofDump() {
return mPendingHprofDump != null;
}
synchronized void setMethodProfilingStatus(MethodProfilingStatus status) {
mProfilingStatus = status;
}
/**
* Returns the method profiling status.
* @see Client#requestMethodProfilingStatus()
*/
public synchronized MethodProfilingStatus getMethodProfilingStatus() {
return mProfilingStatus;
}
/**
* Sets the device-side path to the method profile file being written
* @param pendingMethodProfiling the file being written
*/
void setPendingMethodProfiling(String pendingMethodProfiling) {
mPendingMethodProfiling = pendingMethodProfiling;
}
/**
* Returns the path to the device-side method profiling file being written.
*/
String getPendingMethodProfiling() {
return mPendingMethodProfiling;
}
}