1 /*
2  * Copyright (C) 2008 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 import java.util.List;
18 import java.util.ArrayList;
19 import java.util.LinkedList;
20 import java.util.Map;
21 import java.util.HashMap;
22 import java.io.Serializable;
23 
24 /**
25  * A Dalvik process.
26  */
27 class Proc implements Serializable {
28 
29     private static final long serialVersionUID = 0;
30 
31     /** Parent process. */
32     final Proc parent;
33 
34     /** Process ID. */
35     final int id;
36 
37     /**
38      * Name of this process. We may not have the correct name at first, i.e.
39      * some classes could have been loaded before the process name was set.
40      */
41     String name;
42 
43     /** Child processes. */
44     final List<Proc> children = new ArrayList<Proc>();
45 
46     /** Maps thread ID to operation stack. */
47     transient final Map<Integer, LinkedList<Operation>> stacks
48             = new HashMap<Integer, LinkedList<Operation>>();
49 
50     /** Number of operations. */
51     int operationCount;
52 
53     /** Sequential list of operations that happened in this process. */
54     final List<Operation> operations = new ArrayList<Operation>();
55 
56     /** List of past process names. */
57     final List<String> nameHistory = new ArrayList<String>();
58 
59     /** Constructs a new process. */
Proc(Proc parent, int id)60     Proc(Proc parent, int id) {
61         this.parent = parent;
62         this.id = id;
63     }
64 
65     /** Sets name of this process. */
setName(String name)66     void setName(String name) {
67         if (!name.equals(this.name)) {
68             if (this.name != null) {
69                 nameHistory.add(this.name);
70             }
71             this.name = name;
72         }
73     }
74 
75     /**
76      * Returns true if this process comes from the zygote.
77      */
fromZygote()78     public boolean fromZygote() {
79         return parent != null && parent.name.equals("zygote")
80                 && !name.equals("com.android.development");
81     }
82 
83     /**
84      * Starts an operation.
85      *
86      * @param threadId thread the operation started in
87      * @param loadedClass class operation happened to
88      * @param time the operation started
89      */
startOperation(int threadId, LoadedClass loadedClass, long time, Operation.Type type)90     void startOperation(int threadId, LoadedClass loadedClass, long time,
91             Operation.Type type) {
92         Operation o = new Operation(
93                 this, loadedClass, time, operationCount++, type);
94         operations.add(o);
95 
96         LinkedList<Operation> stack = stacks.get(threadId);
97         if (stack == null) {
98             stack = new LinkedList<Operation>();
99             stacks.put(threadId, stack);
100         }
101 
102         if (!stack.isEmpty()) {
103             stack.getLast().subops.add(o);
104         }
105 
106         stack.add(o);
107     }
108 
109     /**
110      * Ends an operation.
111      *
112      * @param threadId thread the operation ended in
113      * @param loadedClass class operation happened to
114      * @param time the operation ended
115      */
endOperation(int threadId, String className, LoadedClass loadedClass, long time)116     Operation endOperation(int threadId, String className,
117             LoadedClass loadedClass, long time) {
118         LinkedList<Operation> stack = stacks.get(threadId);
119 
120         if (stack == null || stack.isEmpty()) {
121             didNotStart(className);
122             return null;
123         }
124 
125         Operation o = stack.getLast();
126         if (loadedClass != o.loadedClass) {
127             didNotStart(className);
128             return null;
129         }
130 
131         stack.removeLast();
132 
133         o.endTimeNanos = time;
134         return o;
135     }
136 
137     /**
138      * Prints an error indicating that we saw the end of an operation but not
139      * the start. A bug in the logging framework which results in dropped logs
140      * causes this.
141      */
didNotStart(String name)142     private static void didNotStart(String name) {
143         System.err.println("Warning: An operation ended on " + name
144             + " but it never started!");
145     }
146 
147     /**
148      * Prints this process tree to stdout.
149      */
print()150     void print() {
151         print("");
152     }
153 
154     /**
155      * Prints a child proc to standard out.
156      */
print(String prefix)157     private void print(String prefix) {
158         System.out.println(prefix + "id=" + id + ", name=" + name);
159         for (Proc child : children) {
160             child.print(prefix + "    ");
161         }
162     }
163 
164     @Override
toString()165     public String toString() {
166         return this.name;
167     }
168 }
169