| /* |
| * Copyright (C) 2010 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 dalvik.system.profiler; |
| |
| import java.io.DataInputStream; |
| import java.io.IOException; |
| import java.util.HashMap; |
| import java.util.Map; |
| |
| /** |
| * Hprof binary format related constants shared between the |
| * BinaryHprofReader and BinaryHprofWriter. |
| */ |
| public final class BinaryHprof { |
| /** |
| * Currently code only supports 4 byte id size. |
| */ |
| public static final int ID_SIZE = 4; |
| |
| /** |
| * Prefix of valid magic values from the start of a binary hprof file. |
| */ |
| static String MAGIC = "JAVA PROFILE "; |
| |
| /** |
| * Returns the file's magic value as a String if found, otherwise null. |
| */ |
| public static final String readMagic(DataInputStream in) { |
| try { |
| byte[] bytes = new byte[512]; |
| for (int i = 0; i < bytes.length; i++) { |
| byte b = in.readByte(); |
| if (b == '\0') { |
| String string = new String(bytes, 0, i, "UTF-8"); |
| if (string.startsWith(MAGIC)) { |
| return string; |
| } |
| return null; |
| } |
| bytes[i] = b; |
| } |
| return null; |
| } catch (IOException e) { |
| return null; |
| } |
| } |
| |
| public static enum Tag { |
| |
| STRING_IN_UTF8(0x01, -ID_SIZE), |
| LOAD_CLASS(0x02, 4 + ID_SIZE + 4 + ID_SIZE), |
| UNLOAD_CLASS(0x03, 4), |
| STACK_FRAME(0x04, ID_SIZE + ID_SIZE + ID_SIZE + ID_SIZE + 4 + 4), |
| STACK_TRACE(0x05, -(4 + 4 + 4)), |
| ALLOC_SITES(0x06, -(2 + 4 + 4 + 4 + 8 + 8 + 4)), |
| HEAP_SUMMARY(0x07, 4 + 4 + 8 + 8), |
| START_THREAD(0x0a, 4 + ID_SIZE + 4 + ID_SIZE + ID_SIZE + ID_SIZE), |
| END_THREAD(0x0b, 4), |
| HEAP_DUMP(0x0c, -0), |
| HEAP_DUMP_SEGMENT(0x1c, -0), |
| HEAP_DUMP_END(0x2c, 0), |
| CPU_SAMPLES(0x0d, -(4 + 4)), |
| CONTROL_SETTINGS(0x0e, 4 + 2); |
| |
| public final byte tag; |
| |
| /** |
| * Minimum size in bytes. |
| */ |
| public final int minimumSize; |
| |
| /** |
| * Maximum size in bytes. 0 mean no specific limit. |
| */ |
| public final int maximumSize; |
| |
| private Tag(int tag, int size) { |
| this.tag = (byte) tag; |
| if (size > 0) { |
| // fixed size, max and min the same |
| this.minimumSize = size; |
| this.maximumSize = size; |
| } else { |
| // only minimum bound |
| this.minimumSize = -size; |
| this.maximumSize = 0; |
| } |
| } |
| |
| private static final Map<Byte, Tag> BYTE_TO_TAG |
| = new HashMap<Byte, Tag>(); |
| |
| static { |
| for (Tag v : Tag.values()) { |
| BYTE_TO_TAG.put(v.tag, v); |
| } |
| } |
| |
| public static Tag get(byte tag) { |
| return BYTE_TO_TAG.get(tag); |
| } |
| |
| /** |
| * Returns null if the actual size meets expectations, or a |
| * String error message if not. |
| */ |
| public String checkSize(int actual) { |
| if (actual < minimumSize) { |
| return "expected a minimial record size of " + minimumSize + " for " + this |
| + " but received " + actual; |
| } |
| if (maximumSize == 0) { |
| return null; |
| } |
| if (actual > maximumSize) { |
| return "expected a maximum record size of " + maximumSize + " for " + this |
| + " but received " + actual; |
| } |
| return null; |
| } |
| } |
| |
| public static enum ControlSettings { |
| ALLOC_TRACES(0x01), |
| CPU_SAMPLING(0x02); |
| |
| public final int bitmask; |
| |
| private ControlSettings(int bitmask) { |
| this.bitmask = bitmask; |
| } |
| } |
| |
| } |