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