1/*
2 * Copyright (C) 2007 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 com.android.ddmlib;
18
19import java.io.BufferedReader;
20import java.io.ByteArrayInputStream;
21import java.io.IOException;
22import java.io.InputStreamReader;
23import java.nio.ByteBuffer;
24import java.nio.ByteOrder;
25
26/**
27 * Handle thread status updates.
28 */
29final class HandleNativeHeap extends ChunkHandler {
30
31    public static final int CHUNK_NHGT = type("NHGT"); //$NON-NLS-1$
32    public static final int CHUNK_NHSG = type("NHSG"); //$NON-NLS-1$
33    public static final int CHUNK_NHST = type("NHST"); //$NON-NLS-1$
34    public static final int CHUNK_NHEN = type("NHEN"); //$NON-NLS-1$
35
36    private static final HandleNativeHeap mInst = new HandleNativeHeap();
37
38    private HandleNativeHeap() {
39    }
40
41
42    /**
43     * Register for the packets we expect to get from the client.
44     */
45    public static void register(MonitorThread mt) {
46        mt.registerChunkHandler(CHUNK_NHGT, mInst);
47        mt.registerChunkHandler(CHUNK_NHSG, mInst);
48        mt.registerChunkHandler(CHUNK_NHST, mInst);
49        mt.registerChunkHandler(CHUNK_NHEN, mInst);
50    }
51
52    /**
53     * Client is ready.
54     */
55    @Override
56    public void clientReady(Client client) throws IOException {}
57
58    /**
59     * Client went away.
60     */
61    @Override
62    public void clientDisconnected(Client client) {}
63
64    /**
65     * Chunk handler entry point.
66     */
67    @Override
68    public void handleChunk(Client client, int type, ByteBuffer data, boolean isReply, int msgId) {
69
70        Log.d("ddm-nativeheap", "handling " + ChunkHandler.name(type));
71
72        if (type == CHUNK_NHGT) {
73            handleNHGT(client, data);
74        } else if (type == CHUNK_NHST) {
75            // start chunk before any NHSG chunk(s)
76            client.getClientData().getNativeHeapData().clearHeapData();
77        } else if (type == CHUNK_NHEN) {
78            // end chunk after NHSG chunk(s)
79            client.getClientData().getNativeHeapData().sealHeapData();
80        } else if (type == CHUNK_NHSG) {
81            handleNHSG(client, data);
82        } else {
83            handleUnknownChunk(client, type, data, isReply, msgId);
84        }
85
86        client.update(Client.CHANGE_NATIVE_HEAP_DATA);
87    }
88
89    /**
90     * Send an NHGT (Native Thread GeT) request to the client.
91     */
92    public static void sendNHGT(Client client) throws IOException {
93
94        ByteBuffer rawBuf = allocBuffer(0);
95        JdwpPacket packet = new JdwpPacket(rawBuf);
96        ByteBuffer buf = getChunkDataBuf(rawBuf);
97
98        // no data in request message
99
100        finishChunkPacket(packet, CHUNK_NHGT, buf.position());
101        Log.d("ddm-nativeheap", "Sending " + name(CHUNK_NHGT));
102        client.sendAndConsume(packet, mInst);
103
104        rawBuf = allocBuffer(2);
105        packet = new JdwpPacket(rawBuf);
106        buf = getChunkDataBuf(rawBuf);
107
108        buf.put((byte)HandleHeap.WHEN_DISABLE);
109        buf.put((byte)HandleHeap.WHAT_OBJ);
110
111        finishChunkPacket(packet, CHUNK_NHSG, buf.position());
112        Log.d("ddm-nativeheap", "Sending " + name(CHUNK_NHSG));
113        client.sendAndConsume(packet, mInst);
114    }
115
116    /*
117     * Handle our native heap data.
118     */
119    private void handleNHGT(Client client, ByteBuffer data) {
120        ClientData cd = client.getClientData();
121
122        Log.d("ddm-nativeheap", "NHGT: " + data.limit() + " bytes");
123
124        // TODO - process incoming data and save in "cd"
125        byte[] copy = new byte[data.limit()];
126        data.get(copy);
127
128        // clear the previous run
129        cd.clearNativeAllocationInfo();
130
131        ByteBuffer buffer = ByteBuffer.wrap(copy);
132        buffer.order(ByteOrder.LITTLE_ENDIAN);
133
134//        read the header
135//        typedef struct Header {
136//            uint32_t mapSize;
137//            uint32_t allocSize;
138//            uint32_t allocInfoSize;
139//            uint32_t totalMemory;
140//              uint32_t backtraceSize;
141//        };
142
143        int mapSize = buffer.getInt();
144        int allocSize = buffer.getInt();
145        int allocInfoSize = buffer.getInt();
146        int totalMemory = buffer.getInt();
147        int backtraceSize = buffer.getInt();
148
149        Log.d("ddms", "mapSize: " + mapSize);
150        Log.d("ddms", "allocSize: " + allocSize);
151        Log.d("ddms", "allocInfoSize: " + allocInfoSize);
152        Log.d("ddms", "totalMemory: " + totalMemory);
153
154        cd.setTotalNativeMemory(totalMemory);
155
156        // this means that updates aren't turned on.
157        if (allocInfoSize == 0)
158          return;
159
160        if (mapSize > 0) {
161            byte[] maps = new byte[mapSize];
162            buffer.get(maps, 0, mapSize);
163            parseMaps(cd, maps);
164        }
165
166        int iterations = allocSize / allocInfoSize;
167
168        for (int i = 0 ; i < iterations ; i++) {
169            NativeAllocationInfo info = new NativeAllocationInfo(
170                    buffer.getInt() /* size */,
171                    buffer.getInt() /* allocations */);
172
173            for (int j = 0 ; j < backtraceSize ; j++) {
174                long addr = (buffer.getInt()) & 0x00000000ffffffffL;
175
176                if (addr == 0x0) {
177                    // skip past null addresses
178                    continue;
179                }
180
181                info.addStackCallAddress(addr);;
182            }
183
184            cd.addNativeAllocation(info);
185        }
186    }
187
188    private void handleNHSG(Client client, ByteBuffer data) {
189        byte dataCopy[] = new byte[data.limit()];
190        data.rewind();
191        data.get(dataCopy);
192        data = ByteBuffer.wrap(dataCopy);
193        client.getClientData().getNativeHeapData().addHeapData(data);
194
195        if (true) {
196            return;
197        }
198
199        // WORK IN PROGRESS
200
201//        Log.e("ddm-nativeheap", "NHSG: ----------------------------------");
202//        Log.e("ddm-nativeheap", "NHSG: " + data.limit() + " bytes");
203
204        byte[] copy = new byte[data.limit()];
205        data.get(copy);
206
207        ByteBuffer buffer = ByteBuffer.wrap(copy);
208        buffer.order(ByteOrder.BIG_ENDIAN);
209
210        int id = buffer.getInt();
211        int unitsize = buffer.get();
212        long startAddress = buffer.getInt() & 0x00000000ffffffffL;
213        int offset = buffer.getInt();
214        int allocationUnitCount = buffer.getInt();
215
216//        Log.e("ddm-nativeheap", "id: " + id);
217//        Log.e("ddm-nativeheap", "unitsize: " + unitsize);
218//        Log.e("ddm-nativeheap", "startAddress: 0x" + Long.toHexString(startAddress));
219//        Log.e("ddm-nativeheap", "offset: " + offset);
220//        Log.e("ddm-nativeheap", "allocationUnitCount: " + allocationUnitCount);
221//        Log.e("ddm-nativeheap", "end: 0x" +
222//                Long.toHexString(startAddress + unitsize * allocationUnitCount));
223
224        // read the usage
225        while (buffer.position() < buffer.limit()) {
226            int eState = buffer.get() & 0x000000ff;
227            int eLen = (buffer.get() & 0x000000ff) + 1;
228            //Log.e("ddm-nativeheap", "solidity: " + (eState & 0x7) + " - kind: "
229            //        + ((eState >> 3) & 0x7) + " - len: " + eLen);
230        }
231
232
233//        count += unitsize * allocationUnitCount;
234//        Log.e("ddm-nativeheap", "count = " + count);
235
236    }
237
238    private void parseMaps(ClientData cd, byte[] maps) {
239        InputStreamReader input = new InputStreamReader(new ByteArrayInputStream(maps));
240        BufferedReader reader = new BufferedReader(input);
241
242        String line;
243
244        try {
245
246            // most libraries are defined on several lines, so we need to make sure we parse
247            // all the library lines and only add the library at the end
248            long startAddr = 0;
249            long endAddr = 0;
250            String library = null;
251
252            while ((line = reader.readLine()) != null) {
253                Log.d("ddms", "line: " + line);
254                if (line.length() < 16) {
255                    continue;
256                }
257
258                try {
259                    long tmpStart = Long.parseLong(line.substring(0, 8), 16);
260                    long tmpEnd = Long.parseLong(line.substring(9, 17), 16);
261
262                    int index = line.indexOf('/');
263
264                    if (index == -1)
265                        continue;
266
267                    String tmpLib = line.substring(index);
268
269                    if (library == null ||
270                            (library != null && tmpLib.equals(library) == false)) {
271
272                        if (library != null) {
273                            cd.addNativeLibraryMapInfo(startAddr, endAddr, library);
274                            Log.d("ddms", library + "(" + Long.toHexString(startAddr) +
275                                    " - " + Long.toHexString(endAddr) + ")");
276                        }
277
278                        // now init the new library
279                        library = tmpLib;
280                        startAddr = tmpStart;
281                        endAddr = tmpEnd;
282                    } else {
283                        // add the new end
284                        endAddr = tmpEnd;
285                    }
286                } catch (NumberFormatException e) {
287                    e.printStackTrace();
288                }
289            }
290
291            if (library != null) {
292                cd.addNativeLibraryMapInfo(startAddr, endAddr, library);
293                Log.d("ddms", library + "(" + Long.toHexString(startAddr) +
294                        " - " + Long.toHexString(endAddr) + ")");
295            }
296        } catch (IOException e) {
297            e.printStackTrace();
298        }
299    }
300
301
302}
303
304