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
17package dalvik.system.profiler;
18
19import java.io.DataInputStream;
20import java.io.IOException;
21import java.util.HashMap;
22import java.util.Map;
23
24/**
25 * Hprof binary format related constants shared between the
26 * BinaryHprofReader and BinaryHprofWriter.
27 */
28public 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     */
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
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()) {
109                BYTE_TO_TAG.put(v.tag, v);
110            }
111        }
112
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         */
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
143        private ControlSettings(int bitmask) {
144            this.bitmask = bitmask;
145        }
146    }
147
148}
149