1 /*
2  * Copyright (C) 2010 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 dalvik.system.profiler;
18 
19 import java.io.DataInputStream;
20 import java.io.IOException;
21 import java.util.HashMap;
22 import java.util.Map;
23 
24 /**
25  * Hprof binary format related constants shared between the
26  * BinaryHprofReader and BinaryHprofWriter.
27  */
28 public final class BinaryHprof {
29     /**
30      * Currently code only supports 4 byte id size.
31      */
32     public static final int ID_SIZE = 4;
33 
34     /**
35      * Prefix of valid magic values from the start of a binary hprof file.
36      */
37     static String MAGIC = "JAVA PROFILE ";
38 
39     /**
40      * Returns the file's magic value as a String if found, otherwise null.
41      */
readMagic(DataInputStream in)42     public static final String readMagic(DataInputStream in) {
43         try {
44             byte[] bytes = new byte[512];
45             for (int i = 0; i < bytes.length; i++) {
46                 byte b = in.readByte();
47                 if (b == '\0') {
48                     String string = new String(bytes, 0, i, "UTF-8");
49                     if (string.startsWith(MAGIC)) {
50                         return string;
51                     }
52                     return null;
53                 }
54                 bytes[i] = b;
55             }
56             return null;
57         } catch (IOException e) {
58             return null;
59         }
60     }
61 
62     public static enum Tag {
63 
64         STRING_IN_UTF8(0x01, -ID_SIZE),
65         LOAD_CLASS(0x02, 4 + ID_SIZE + 4 + ID_SIZE),
66         UNLOAD_CLASS(0x03, 4),
67         STACK_FRAME(0x04, ID_SIZE + ID_SIZE + ID_SIZE + ID_SIZE + 4 + 4),
68         STACK_TRACE(0x05, -(4 + 4 + 4)),
69         ALLOC_SITES(0x06, -(2 + 4 + 4 + 4 + 8 + 8 + 4)),
70         HEAP_SUMMARY(0x07, 4 + 4 + 8 + 8),
71         START_THREAD(0x0a, 4 + ID_SIZE + 4 + ID_SIZE + ID_SIZE + ID_SIZE),
72         END_THREAD(0x0b, 4),
73         HEAP_DUMP(0x0c, -0),
74         HEAP_DUMP_SEGMENT(0x1c, -0),
75         HEAP_DUMP_END(0x2c, 0),
76         CPU_SAMPLES(0x0d, -(4 + 4)),
77         CONTROL_SETTINGS(0x0e, 4 + 2);
78 
79         public final byte tag;
80 
81         /**
82          * Minimum size in bytes.
83          */
84         public final int minimumSize;
85 
86         /**
87          * Maximum size in bytes. 0 mean no specific limit.
88          */
89         public final int maximumSize;
90 
Tag(int tag, int size)91         private Tag(int tag, int size) {
92             this.tag = (byte) tag;
93             if (size > 0) {
94                 // fixed size, max and min the same
95                 this.minimumSize = size;
96                 this.maximumSize = size;
97             } else {
98                 // only minimum bound
99                 this.minimumSize = -size;
100                 this.maximumSize = 0;
101             }
102         }
103 
104         private static final Map<Byte, Tag> BYTE_TO_TAG
105                 = new HashMap<Byte, Tag>();
106 
107         static {
108             for (Tag v : Tag.values()) {
BYTE_TO_TAG.put(v.tag, v)109                 BYTE_TO_TAG.put(v.tag, v);
110             }
111         }
112 
get(byte tag)113         public static Tag get(byte tag) {
114             return BYTE_TO_TAG.get(tag);
115         }
116 
117         /**
118          * Returns null if the actual size meets expectations, or a
119          * String error message if not.
120          */
checkSize(int actual)121         public String checkSize(int actual) {
122             if (actual < minimumSize) {
123                 return "expected a minimial record size of " + minimumSize + " for " + this
124                         + " but received " + actual;
125             }
126             if (maximumSize == 0) {
127                 return null;
128             }
129             if (actual > maximumSize) {
130                 return "expected a maximum record size of " + maximumSize + " for " + this
131                         + " but received " + actual;
132             }
133             return null;
134         }
135     }
136 
137     public static enum ControlSettings {
138         ALLOC_TRACES(0x01),
139         CPU_SAMPLING(0x02);
140 
141         public final int bitmask;
142 
ControlSettings(int bitmask)143         private ControlSettings(int bitmask) {
144             this.bitmask = bitmask;
145         }
146     }
147 
148 }
149