1/*
2 * Copyright (C) 2009 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
17package android.ddm;
18
19import org.apache.harmony.dalvik.ddmc.Chunk;
20import org.apache.harmony.dalvik.ddmc.ChunkHandler;
21import org.apache.harmony.dalvik.ddmc.DdmServer;
22import android.os.Debug;
23import android.util.Log;
24import java.io.IOException;
25import java.nio.ByteBuffer;
26
27/**
28 * Handle profiling requests.
29 */
30public class DdmHandleProfiling extends ChunkHandler {
31
32    public static final int CHUNK_MPRS = type("MPRS");
33    public static final int CHUNK_MPRE = type("MPRE");
34    public static final int CHUNK_MPSS = type("MPSS");
35    public static final int CHUNK_MPSE = type("MPSE");
36    public static final int CHUNK_MPRQ = type("MPRQ");
37
38    private static DdmHandleProfiling mInstance = new DdmHandleProfiling();
39
40
41    /* singleton, do not instantiate */
42    private DdmHandleProfiling() {}
43
44    /**
45     * Register for the messages we're interested in.
46     */
47    public static void register() {
48        DdmServer.registerHandler(CHUNK_MPRS, mInstance);
49        DdmServer.registerHandler(CHUNK_MPRE, mInstance);
50        DdmServer.registerHandler(CHUNK_MPSS, mInstance);
51        DdmServer.registerHandler(CHUNK_MPSE, mInstance);
52        DdmServer.registerHandler(CHUNK_MPRQ, mInstance);
53    }
54
55    /**
56     * Called when the DDM server connects.  The handler is allowed to
57     * send messages to the server.
58     */
59    public void connected() {}
60
61    /**
62     * Called when the DDM server disconnects.  Can be used to disable
63     * periodic transmissions or clean up saved state.
64     */
65    public void disconnected() {}
66
67    /**
68     * Handle a chunk of data.
69     */
70    public Chunk handleChunk(Chunk request) {
71        if (false)
72            Log.v("ddm-heap", "Handling " + name(request.type) + " chunk");
73        int type = request.type;
74
75        if (type == CHUNK_MPRS) {
76            return handleMPRS(request);
77        } else if (type == CHUNK_MPRE) {
78            return handleMPRE(request);
79        } else if (type == CHUNK_MPSS) {
80            return handleMPSS(request);
81        } else if (type == CHUNK_MPSE) {
82            return handleMPSE(request);
83        } else if (type == CHUNK_MPRQ) {
84            return handleMPRQ(request);
85        } else {
86            throw new RuntimeException("Unknown packet "
87                + ChunkHandler.name(type));
88        }
89    }
90
91    /*
92     * Handle a "Method PRofiling Start" request.
93     */
94    private Chunk handleMPRS(Chunk request) {
95        ByteBuffer in = wrapChunk(request);
96
97        int bufferSize = in.getInt();
98        int flags = in.getInt();
99        int len = in.getInt();
100        String fileName = getString(in, len);
101        if (false)
102            Log.v("ddm-heap", "Method profiling start: filename='" + fileName
103                + "', size=" + bufferSize + ", flags=" + flags);
104
105        try {
106            Debug.startMethodTracing(fileName, bufferSize, flags);
107            return null;        // empty response
108        } catch (RuntimeException re) {
109            return createFailChunk(1, re.getMessage());
110        }
111    }
112
113    /*
114     * Handle a "Method PRofiling End" request.
115     */
116    private Chunk handleMPRE(Chunk request) {
117        byte result;
118
119        try {
120            Debug.stopMethodTracing();
121            result = 0;
122        } catch (RuntimeException re) {
123            Log.w("ddm-heap", "Method profiling end failed: "
124                + re.getMessage());
125            result = 1;
126        }
127
128        /* create a non-empty reply so the handler fires on completion */
129        byte[] reply = { result };
130        return new Chunk(CHUNK_MPRE, reply, 0, reply.length);
131    }
132
133    /*
134     * Handle a "Method Profiling w/Streaming Start" request.
135     */
136    private Chunk handleMPSS(Chunk request) {
137        ByteBuffer in = wrapChunk(request);
138
139        int bufferSize = in.getInt();
140        int flags = in.getInt();
141        if (false) {
142            Log.v("ddm-heap", "Method prof stream start: size=" + bufferSize
143                + ", flags=" + flags);
144        }
145
146        try {
147            Debug.startMethodTracingDdms(bufferSize, flags);
148            return null;        // empty response
149        } catch (RuntimeException re) {
150            return createFailChunk(1, re.getMessage());
151        }
152    }
153
154    /*
155     * Handle a "Method Profiling w/Streaming End" request.
156     */
157    private Chunk handleMPSE(Chunk request) {
158        byte result;
159
160        if (false) {
161            Log.v("ddm-heap", "Method prof stream end");
162        }
163
164        try {
165            Debug.stopMethodTracing();
166            result = 0;
167        } catch (RuntimeException re) {
168            Log.w("ddm-heap", "Method prof stream end failed: "
169                + re.getMessage());
170            return createFailChunk(1, re.getMessage());
171        }
172
173        /* VM sent the (perhaps very large) response directly */
174        return null;
175    }
176
177    /*
178     * Handle a "Method PRofiling Query" request.
179     */
180    private Chunk handleMPRQ(Chunk request) {
181        int result = Debug.isMethodTracingActive() ? 1 : 0;
182
183        /* create a non-empty reply so the handler fires on completion */
184        byte[] reply = { (byte) result };
185        return new Chunk(CHUNK_MPRQ, reply, 0, reply.length);
186    }
187}
188
189