1231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn/*
2231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn * Copyright (C) 2008 The Android Open Source Project
3231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn *
4231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn * Licensed under the Apache License, Version 2.0 (the "License");
5231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn * you may not use this file except in compliance with the License.
6231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn * You may obtain a copy of the License at
7231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn *
8231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn *      http://www.apache.org/licenses/LICENSE-2.0
9231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn *
10231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn * Unless required by applicable law or agreed to in writing, software
11231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn * distributed under the License is distributed on an "AS IS" BASIS,
12231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn * See the License for the specific language governing permissions and
14231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn * limitations under the License.
15231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn */
16231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn
17231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn/**
18231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn * One line from the loaded-classes file.
19231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn */
20231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackbornclass Record {
21231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn
22231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn    /**
23231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn     * The delimiter character we use, {@code :}, conflicts with some other
24231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn     * names. In that case, manually replace the delimiter with something else.
25231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn     */
26231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn    private static final String[] REPLACE_CLASSES = {
27231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            "com.google.android.apps.maps:FriendService",
28231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            "com.google.android.apps.maps\\u003AFriendService",
29231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            "com.google.android.apps.maps:driveabout",
30231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            "com.google.android.apps.maps\\u003Adriveabout",
31763631cd247e21b167063023e7dd1395e05ebbf6Jeff Brown            "com.google.android.apps.maps:GoogleLocationService",
32763631cd247e21b167063023e7dd1395e05ebbf6Jeff Brown            "com.google.android.apps.maps\\u003AGoogleLocationService",
33763631cd247e21b167063023e7dd1395e05ebbf6Jeff Brown            "com.google.android.apps.maps:LocationFriendService",
34763631cd247e21b167063023e7dd1395e05ebbf6Jeff Brown            "com.google.android.apps.maps\\u003ALocationFriendService",
35763631cd247e21b167063023e7dd1395e05ebbf6Jeff Brown            "com.google.android.apps.maps:MapsBackgroundService",
36763631cd247e21b167063023e7dd1395e05ebbf6Jeff Brown            "com.google.android.apps.maps\\u003AMapsBackgroundService",
37763631cd247e21b167063023e7dd1395e05ebbf6Jeff Brown            "com.google.android.apps.maps:NetworkLocationService",
38763631cd247e21b167063023e7dd1395e05ebbf6Jeff Brown            "com.google.android.apps.maps\\u003ANetworkLocationService",
39763631cd247e21b167063023e7dd1395e05ebbf6Jeff Brown            "com.android.chrome:sandboxed_process",
40763631cd247e21b167063023e7dd1395e05ebbf6Jeff Brown            "com.android.chrome\\u003Asandboxed_process",
41763631cd247e21b167063023e7dd1395e05ebbf6Jeff Brown            "com.android.fakeoemfeatures:background",
42231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            "com.android.fakeoemfeatures\\u003Abackground",
43231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            "com.android.fakeoemfeatures:core",
44231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            "com.android.fakeoemfeatures\\u003Acore",
45231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            "com.google.android.music:main",
46231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            "com.google.android.music\\u003Amain",
47231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            "com.google.android.music:ui",
48231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            "com.google.android.music\\u003Aui",
49231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            "com.google.android.setupwarlock:broker",
50231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            "com.google.android.setupwarlock\\u003Abroker",
51231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            "android:ui",
52231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            "android\\u003Aui",
53231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn    };
54231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn
55231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn    enum Type {
56231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        /** Start of initialization. */
57231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        START_LOAD,
58231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn
591afd1c90ebe789b8d3a137004127a50d2db7e3b5Dianne Hackborn        /** End of initialization. */
60231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        END_LOAD,
61231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn
62231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        /** Start of initialization. */
63231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        START_INIT,
641afd1c90ebe789b8d3a137004127a50d2db7e3b5Dianne Hackborn
651afd1c90ebe789b8d3a137004127a50d2db7e3b5Dianne Hackborn        /** End of initialization. */
66231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        END_INIT
67231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn    }
68231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn
69231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn    /** Parent process ID. */
70231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn    final int ppid;
71231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn
72231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn    /** Process ID. */
73231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn    final int pid;
74231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn
75231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn    /** Thread ID. */
76231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn    final int tid;
77231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn
78231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn    /** Process name. */
79231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn    final String processName;
80231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn
81231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn    /** Class loader pointer. */
82231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn    final int classLoader;
83231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn
84231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn    /** Type of record. */
85231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn    final Type type;
86231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn
87231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn    /** Name of loaded class. */
88231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn    final String className;
89231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn
90231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn    /** Record time (ns). */
918bdf5935c0db4a66ab33a10b43398d2523cfa15dDianne Hackborn    final long time;
92231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn
93231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn    /** Source file line# */
94231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn    int sourceLineNumber;
95231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn
96231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn    /**
97231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn     * Parses a line from the loaded-classes file.
98231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn     */
99231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn    Record(String line, int lineNum) {
100231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        char typeChar = line.charAt(0);
101231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        switch (typeChar) {
102231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            case '>': type = Type.START_LOAD; break;
1038bdf5935c0db4a66ab33a10b43398d2523cfa15dDianne Hackborn            case '<': type = Type.END_LOAD; break;
104231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            case '+': type = Type.START_INIT; break;
105231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            case '-': type = Type.END_INIT; break;
106231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            default: throw new AssertionError("Bad line: " + line);
107231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        }
108231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn
109231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        sourceLineNumber = lineNum;
110231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn
111231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        for (int i = 0; i < REPLACE_CLASSES.length; i+= 2) {
112231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            line = line.replace(REPLACE_CLASSES[i], REPLACE_CLASSES[i+1]);
113231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        }
114231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn
115231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        line = line.substring(1);
116231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        String[] parts = line.split(":");
117231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn
118231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        ppid = Integer.parseInt(parts[0]);
119231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        pid = Integer.parseInt(parts[1]);
120231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        tid = Integer.parseInt(parts[2]);
121231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn
122231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        processName = decode(parts[3]).intern();
123231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn
124231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        classLoader = Integer.parseInt(parts[4]);
1258bdf5935c0db4a66ab33a10b43398d2523cfa15dDianne Hackborn        className = vmTypeToLanguage(decode(parts[5])).intern();
126231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn
127231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        time = Long.parseLong(parts[6]);
128231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn    }
129231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn
130231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn    /**
131231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn     * Decode any escaping that may have been written to the log line.
132231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn     *
133231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn     * Supports unicode-style escaping:  \\uXXXX = character in hex
134231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn     *
135231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn     * @param rawField the field as it was written into the log
136231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn     * @result the same field with any escaped characters replaced
137231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn     */
138231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn    String decode(String rawField) {
139231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        String result = rawField;
140231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        int offset = result.indexOf("\\u");
141231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        while (offset >= 0) {
142231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            String before = result.substring(0, offset);
143231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            String escaped = result.substring(offset+2, offset+6);
144231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            String after = result.substring(offset+6);
145231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn
146231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            result = String.format("%s%c%s", before, Integer.parseInt(escaped, 16), after);
147231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn
148231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            // find another but don't recurse
149231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            offset = result.indexOf("\\u", offset + 1);
150231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        }
151231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        return result;
152231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn    }
153231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn
154231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn    /**
155231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn     * Converts a VM-style name to a language-style name.
156231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn     */
157231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn    String vmTypeToLanguage(String typeName) {
158231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        // if the typename is (null), just return it as-is.  This is probably in dexopt and
159231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        // will be discarded anyway.  NOTE: This corresponds to the case in dalvik/vm/oo/Class.c
160231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        // where dvmLinkClass() returns false and we clean up and exit.
161231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        if ("(null)".equals(typeName)) {
162231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            return typeName;
163231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        }
164231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn
165231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        if (!typeName.startsWith("L") || !typeName.endsWith(";") ) {
166231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            throw new AssertionError("Bad name: " + typeName + " in line " + sourceLineNumber);
167231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        }
168231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn
169        typeName = typeName.substring(1, typeName.length() - 1);
170        return typeName.replace("/", ".");
171    }
172}
173