/*
* 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.io.Serializable;
import java.io.IOException;
import java.io.Writer;
import java.io.BufferedWriter;
import java.io.OutputStreamWriter;
import java.io.FileOutputStream;
import java.io.FileInputStream;
import java.io.ObjectInputStream;
import java.io.BufferedInputStream;
import java.io.ObjectOutputStream;
import java.io.BufferedOutputStream;
import java.util.Map;
import java.util.HashMap;
import java.util.Set;
import java.util.TreeSet;
import java.util.Arrays;
import java.nio.charset.Charset;
/**
* Root of our data model.
*/
public class Root implements Serializable {
private static final long serialVersionUID = 0;
/** pid -> Proc */
final Map<Integer, Proc> processes = new HashMap<Integer, Proc>();
/** Class name -> LoadedClass */
final Map<String, LoadedClass> loadedClasses
= new HashMap<String, LoadedClass>();
MemoryUsage baseline = MemoryUsage.baseline();
/**
* Records class loads and initializations.
*/
void indexClassOperation(Record record) {
Proc process = processes.get(record.pid);
// Ignore dexopt output. It loads applications classes through the
// system class loader and messes us up.
if (record.processName.equals("dexopt")) {
return;
}
String name = record.className;
LoadedClass loadedClass = loadedClasses.get(name);
Operation o = null;
switch (record.type) {
case START_LOAD:
case START_INIT:
if (loadedClass == null) {
loadedClass = new LoadedClass(
name, record.classLoader == 0);
if (loadedClass.systemClass) {
// Only measure memory for classes in the boot
// classpath.
loadedClass.measureMemoryUsage();
}
loadedClasses.put(name, loadedClass);
}
break;
case END_LOAD:
case END_INIT:
o = process.endOperation(record.tid, record.className,
loadedClass, record.time);
if (o == null) {
return;
}
}
switch (record.type) {
case START_LOAD:
process.startOperation(record.tid, loadedClass, record.time,
Operation.Type.LOAD);
break;
case START_INIT:
process.startOperation(record.tid, loadedClass, record.time,
Operation.Type.INIT);
break;
case END_LOAD:
loadedClass.loads.add(o);
break;
case END_INIT:
loadedClass.initializations.add(o);
break;
}
}
/**
* Indexes information about the process from the given record.
*/
void indexProcess(Record record) {
Proc proc = processes.get(record.pid);
if (proc == null) {
// Create a new process object.
Proc parent = processes.get(record.ppid);
proc = new Proc(parent, record.pid);
processes.put(proc.id, proc);
if (parent != null) {
parent.children.add(proc);
}
}
proc.setName(record.processName);
}
/**
* Writes this graph to a file.
*/
void toFile(String fileName) throws IOException {
FileOutputStream out = new FileOutputStream(fileName);
ObjectOutputStream oout = new ObjectOutputStream(
new BufferedOutputStream(out));
System.err.println("Writing object model...");
oout.writeObject(this);
oout.close();
System.err.println("Done!");
}
/**
* Reads Root from a file.
*/
static Root fromFile(String fileName)
throws IOException, ClassNotFoundException {
FileInputStream fin = new FileInputStream(fileName);
ObjectInputStream oin = new ObjectInputStream(
new BufferedInputStream(fin));
Root root = (Root) oin.readObject();
oin.close();
return root;
}
}