diff options
Diffstat (limited to 'tools/preload/Record.java')
-rw-r--r-- | tools/preload/Record.java | 182 |
1 files changed, 182 insertions, 0 deletions
diff --git a/tools/preload/Record.java b/tools/preload/Record.java new file mode 100644 index 0000000..d0a2af4 --- /dev/null +++ b/tools/preload/Record.java @@ -0,0 +1,182 @@ +/* + * Copyright (C) 2008 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. + */ + +/** + * One line from the loaded-classes file. + */ +class Record { + + /** + * The delimiter character we use, {@code :}, conflicts with some other + * names. In that case, manually replace the delimiter with something else. + */ + private static final String[] REPLACE_CLASSES = { + "com.google.android.apps.maps:FriendService", + "com.google.android.apps.maps\\u003AFriendService", + "com.google.android.apps.maps:driveabout", + "com.google.android.apps.maps\\u003Adriveabout", + "com.google.android.apps.maps:GoogleLocationService", + "com.google.android.apps.maps\\u003AGoogleLocationService", + "com.google.android.apps.maps:LocationFriendService", + "com.google.android.apps.maps\\u003ALocationFriendService", + "com.google.android.apps.maps:MapsBackgroundService", + "com.google.android.apps.maps\\u003AMapsBackgroundService", + "com.google.android.apps.maps:NetworkLocationService", + "com.google.android.apps.maps\\u003ANetworkLocationService", + "com.android.chrome:sandboxed_process", + "com.android.chrome\\u003Asandboxed_process", + "com.android.fakeoemfeatures:background", + "com.android.fakeoemfeatures\\u003Abackground", + "com.android.fakeoemfeatures:core", + "com.android.fakeoemfeatures\\u003Acore", + "com.android.launcher:wallpaper_chooser", + "com.android.launcher\\u003Awallpaper_chooser", + "com.android.nfc:handover", + "com.android.nfc\\u003Ahandover", + "com.google.android.music:main", + "com.google.android.music\\u003Amain", + "com.google.android.music:ui", + "com.google.android.music\\u003Aui", + "com.google.android.setupwarlock:broker", + "com.google.android.setupwarlock\\u003Abroker", + "mobi.mgeek.TunnyBrowser:DolphinNotification", + "mobi.mgeek.TunnyBrowser\\u003ADolphinNotification", + "com.qo.android.sp.oem:Quickword", + "com.qo.android.sp.oem\\u003AQuickword", + "android:ui", + "android\\u003Aui", + "system:ui", + "system\\u003Aui", + }; + + enum Type { + /** Start of initialization. */ + START_LOAD, + + /** End of initialization. */ + END_LOAD, + + /** Start of initialization. */ + START_INIT, + + /** End of initialization. */ + END_INIT + } + + /** Parent process ID. */ + final int ppid; + + /** Process ID. */ + final int pid; + + /** Thread ID. */ + final int tid; + + /** Process name. */ + final String processName; + + /** Class loader pointer. */ + final int classLoader; + + /** Type of record. */ + final Type type; + + /** Name of loaded class. */ + final String className; + + /** Record time (ns). */ + final long time; + + /** Source file line# */ + int sourceLineNumber; + + /** + * Parses a line from the loaded-classes file. + */ + Record(String line, int lineNum) { + char typeChar = line.charAt(0); + switch (typeChar) { + case '>': type = Type.START_LOAD; break; + case '<': type = Type.END_LOAD; break; + case '+': type = Type.START_INIT; break; + case '-': type = Type.END_INIT; break; + default: throw new AssertionError("Bad line: " + line); + } + + sourceLineNumber = lineNum; + + for (int i = 0; i < REPLACE_CLASSES.length; i+= 2) { + line = line.replace(REPLACE_CLASSES[i], REPLACE_CLASSES[i+1]); + } + + line = line.substring(1); + String[] parts = line.split(":"); + + ppid = Integer.parseInt(parts[0]); + pid = Integer.parseInt(parts[1]); + tid = Integer.parseInt(parts[2]); + + processName = decode(parts[3]).intern(); + + classLoader = Integer.parseInt(parts[4]); + className = vmTypeToLanguage(decode(parts[5])).intern(); + + time = Long.parseLong(parts[6]); + } + + /** + * Decode any escaping that may have been written to the log line. + * + * Supports unicode-style escaping: \\uXXXX = character in hex + * + * @param rawField the field as it was written into the log + * @result the same field with any escaped characters replaced + */ + String decode(String rawField) { + String result = rawField; + int offset = result.indexOf("\\u"); + while (offset >= 0) { + String before = result.substring(0, offset); + String escaped = result.substring(offset+2, offset+6); + String after = result.substring(offset+6); + + result = String.format("%s%c%s", before, Integer.parseInt(escaped, 16), after); + + // find another but don't recurse + offset = result.indexOf("\\u", offset + 1); + } + return result; + } + + /** + * Converts a VM-style name to a language-style name. + */ + String vmTypeToLanguage(String typeName) { + // if the typename is (null), just return it as-is. This is probably in dexopt and + // will be discarded anyway. NOTE: This corresponds to the case in dalvik/vm/oo/Class.c + // where dvmLinkClass() returns false and we clean up and exit. + if ("(null)".equals(typeName)) { + return typeName; + } + + if (!typeName.startsWith("L") || !typeName.endsWith(";") ) { + throw new AssertionError("Bad name: " + typeName + " in line " + sourceLineNumber); + } + + typeName = typeName.substring(1, typeName.length() - 1); + return typeName.replace("/", "."); + } +} |