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