| /* |
| * 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. |
| */ |
| |
| import java.util.List; |
| import java.util.ArrayList; |
| import java.util.LinkedList; |
| import java.util.Map; |
| import java.util.HashMap; |
| import java.io.Serializable; |
| |
| /** |
| * A Dalvik process. |
| */ |
| class Proc implements Serializable { |
| |
| private static final long serialVersionUID = 0; |
| |
| /** Parent process. */ |
| final Proc parent; |
| |
| /** Process ID. */ |
| final int id; |
| |
| /** |
| * Name of this process. We may not have the correct name at first, i.e. |
| * some classes could have been loaded before the process name was set. |
| */ |
| String name; |
| |
| /** Child processes. */ |
| final List<Proc> children = new ArrayList<Proc>(); |
| |
| /** Maps thread ID to operation stack. */ |
| transient final Map<Integer, LinkedList<Operation>> stacks |
| = new HashMap<Integer, LinkedList<Operation>>(); |
| |
| /** Number of operations. */ |
| int operationCount; |
| |
| /** Sequential list of operations that happened in this process. */ |
| final List<Operation> operations = new ArrayList<Operation>(); |
| |
| /** List of past process names. */ |
| final List<String> nameHistory = new ArrayList<String>(); |
| |
| /** Constructs a new process. */ |
| Proc(Proc parent, int id) { |
| this.parent = parent; |
| this.id = id; |
| } |
| |
| /** Sets name of this process. */ |
| void setName(String name) { |
| if (!name.equals(this.name)) { |
| if (this.name != null) { |
| nameHistory.add(this.name); |
| } |
| this.name = name; |
| } |
| } |
| |
| /** |
| * Returns true if this process comes from the zygote. |
| */ |
| public boolean fromZygote() { |
| return parent != null && parent.name.equals("zygote") |
| && !name.equals("com.android.development"); |
| } |
| |
| /** |
| * Starts an operation. |
| * |
| * @param threadId thread the operation started in |
| * @param loadedClass class operation happened to |
| * @param time the operation started |
| */ |
| void startOperation(int threadId, LoadedClass loadedClass, long time, |
| Operation.Type type) { |
| Operation o = new Operation( |
| this, loadedClass, time, operationCount++, type); |
| operations.add(o); |
| |
| LinkedList<Operation> stack = stacks.get(threadId); |
| if (stack == null) { |
| stack = new LinkedList<Operation>(); |
| stacks.put(threadId, stack); |
| } |
| |
| if (!stack.isEmpty()) { |
| stack.getLast().subops.add(o); |
| } |
| |
| stack.add(o); |
| } |
| |
| /** |
| * Ends an operation. |
| * |
| * @param threadId thread the operation ended in |
| * @param loadedClass class operation happened to |
| * @param time the operation ended |
| */ |
| Operation endOperation(int threadId, String className, |
| LoadedClass loadedClass, long time) { |
| LinkedList<Operation> stack = stacks.get(threadId); |
| |
| if (stack == null || stack.isEmpty()) { |
| didNotStart(className); |
| return null; |
| } |
| |
| Operation o = stack.getLast(); |
| if (loadedClass != o.loadedClass) { |
| didNotStart(className); |
| return null; |
| } |
| |
| stack.removeLast(); |
| |
| o.endTimeNanos = time; |
| return o; |
| } |
| |
| /** |
| * Prints an error indicating that we saw the end of an operation but not |
| * the start. A bug in the logging framework which results in dropped logs |
| * causes this. |
| */ |
| private static void didNotStart(String name) { |
| System.err.println("Warning: An operation ended on " + name |
| + " but it never started!"); |
| } |
| |
| /** |
| * Prints this process tree to stdout. |
| */ |
| void print() { |
| print(""); |
| } |
| |
| /** |
| * Prints a child proc to standard out. |
| */ |
| private void print(String prefix) { |
| System.out.println(prefix + "id=" + id + ", name=" + name); |
| for (Proc child : children) { |
| child.print(prefix + " "); |
| } |
| } |
| |
| @Override |
| public String toString() { |
| return this.name; |
| } |
| } |