1282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/* 2282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Copyright (C) 2008 The Android Open Source Project 3282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * 4282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Licensed under the Apache License, Version 2.0 (the "License"); 5282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * you may not use this file except in compliance with the License. 6282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * You may obtain a copy of the License at 7282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * 8282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * http://www.apache.org/licenses/LICENSE-2.0 9282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * 10282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Unless required by applicable law or agreed to in writing, software 11282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * distributed under the License is distributed on an "AS IS" BASIS, 12282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * See the License for the specific language governing permissions and 14282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * limitations under the License. 15282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */ 16282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 17282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport java.util.List; 18282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport java.util.ArrayList; 19282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport java.util.LinkedList; 20282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport java.util.Map; 21282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport java.util.HashMap; 22282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport java.io.Serializable; 23282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 24282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/** 25282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * A Dalvik process. 26282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */ 27282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiclass Proc implements Serializable { 28282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 29282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski private static final long serialVersionUID = 0; 30282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 31282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski /** Parent process. */ 32282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski final Proc parent; 33282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 34282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski /** Process ID. */ 35282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski final int id; 36282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 37282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski /** 38282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Name of this process. We may not have the correct name at first, i.e. 39282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * some classes could have been loaded before the process name was set. 40282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */ 41282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski String name; 42282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 43282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski /** Child processes. */ 44282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski final List<Proc> children = new ArrayList<Proc>(); 45282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 46282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski /** Maps thread ID to operation stack. */ 47282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski transient final Map<Integer, LinkedList<Operation>> stacks 48282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski = new HashMap<Integer, LinkedList<Operation>>(); 49282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 50282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski /** Number of operations. */ 51282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski int operationCount; 52282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 53282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski /** Sequential list of operations that happened in this process. */ 54282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski final List<Operation> operations = new ArrayList<Operation>(); 55282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 56282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski /** List of past process names. */ 57282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski final List<String> nameHistory = new ArrayList<String>(); 58282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 59282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski /** Constructs a new process. */ 60282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski Proc(Proc parent, int id) { 61282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski this.parent = parent; 62282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski this.id = id; 63282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 64282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 65282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski /** Sets name of this process. */ 66282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski void setName(String name) { 67282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if (!name.equals(this.name)) { 68282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if (this.name != null) { 69282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski nameHistory.add(this.name); 70282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 71282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski this.name = name; 72282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 73282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 74282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 75282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski /** 76282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Returns true if this process comes from the zygote. 77282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */ 78282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski public boolean fromZygote() { 79282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski return parent != null && parent.name.equals("zygote") 80282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski && !name.equals("com.android.development"); 81282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 82282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 83282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski /** 84282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Starts an operation. 85282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * 86282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * @param threadId thread the operation started in 87282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * @param loadedClass class operation happened to 88282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * @param time the operation started 89282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */ 90282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski void startOperation(int threadId, LoadedClass loadedClass, long time, 91282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski Operation.Type type) { 92282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski Operation o = new Operation( 93282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski this, loadedClass, time, operationCount++, type); 94282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski operations.add(o); 95282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 96282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski LinkedList<Operation> stack = stacks.get(threadId); 97282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if (stack == null) { 98282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski stack = new LinkedList<Operation>(); 99282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski stacks.put(threadId, stack); 100282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 101282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 102282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if (!stack.isEmpty()) { 103282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski stack.getLast().subops.add(o); 104282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 105282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 106282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski stack.add(o); 107282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 108282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 109282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski /** 110282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Ends an operation. 111282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * 112282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * @param threadId thread the operation ended in 113282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * @param loadedClass class operation happened to 114282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * @param time the operation ended 115282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */ 116282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski Operation endOperation(int threadId, String className, 117282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski LoadedClass loadedClass, long time) { 118282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski LinkedList<Operation> stack = stacks.get(threadId); 119282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 120282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if (stack == null || stack.isEmpty()) { 121282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski didNotStart(className); 122282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski return null; 123282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 124282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 125282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski Operation o = stack.getLast(); 126282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if (loadedClass != o.loadedClass) { 127282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski didNotStart(className); 128282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski return null; 129282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 130282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 131282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski stack.removeLast(); 132282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 133282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski o.endTimeNanos = time; 134282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski return o; 135282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 136282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 137282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski /** 138282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Prints an error indicating that we saw the end of an operation but not 139282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * the start. A bug in the logging framework which results in dropped logs 140282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * causes this. 141282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */ 142282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski private static void didNotStart(String name) { 143282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski System.err.println("Warning: An operation ended on " + name 144282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski + " but it never started!"); 145282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 146282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 147282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski /** 148282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Prints this process tree to stdout. 149282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */ 150282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski void print() { 151282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski print(""); 152282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 153282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 154282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski /** 155282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Prints a child proc to standard out. 156282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */ 157282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski private void print(String prefix) { 158282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski System.out.println(prefix + "id=" + id + ", name=" + name); 159282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski for (Proc child : children) { 160282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski child.print(prefix + " "); 161282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 162282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 163282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 164282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski @Override 165282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski public String toString() { 166282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski return this.name; 167282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 168282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski} 169