| /* | 
 |  * 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; | 
 |     } | 
 | } |