DdmHandleHello.java revision 0c1761bd37815c3776608a19c8e11d862b3e910c
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 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.util.Log;
23import android.os.Debug;
24import android.os.UserHandle;
25
26import java.nio.ByteBuffer;
27
28/**
29 * Handle "hello" messages and feature discovery.
30 */
31public class DdmHandleHello extends ChunkHandler {
32
33    public static final int CHUNK_HELO = type("HELO");
34    public static final int CHUNK_WAIT = type("WAIT");
35    public static final int CHUNK_FEAT = type("FEAT");
36
37    private static DdmHandleHello mInstance = new DdmHandleHello();
38
39    private static final String[] NATIVE_FEATURES = new String[] { "opengl-tracing" };
40
41    /* singleton, do not instantiate */
42    private DdmHandleHello() {}
43
44    /**
45     * Register for the messages we're interested in.
46     */
47    public static void register() {
48        DdmServer.registerHandler(CHUNK_HELO, mInstance);
49        DdmServer.registerHandler(CHUNK_FEAT, mInstance);
50    }
51
52    /**
53     * Called when the DDM server connects.  The handler is allowed to
54     * send messages to the server.
55     */
56    public void connected() {
57        if (false)
58            Log.v("ddm-hello", "Connected!");
59
60        if (false) {
61            /* test spontaneous transmission */
62            byte[] data = new byte[] { 0, 1, 2, 3, 4, -4, -3, -2, -1, 127 };
63            Chunk testChunk =
64                new Chunk(ChunkHandler.type("TEST"), data, 1, data.length-2);
65            DdmServer.sendChunk(testChunk);
66        }
67    }
68
69    /**
70     * Called when the DDM server disconnects.  Can be used to disable
71     * periodic transmissions or clean up saved state.
72     */
73    public void disconnected() {
74        if (false)
75            Log.v("ddm-hello", "Disconnected!");
76    }
77
78    /**
79     * Handle a chunk of data.
80     */
81    public Chunk handleChunk(Chunk request) {
82        if (false)
83            Log.v("ddm-heap", "Handling " + name(request.type) + " chunk");
84        int type = request.type;
85
86        if (type == CHUNK_HELO) {
87            return handleHELO(request);
88        } else if (type == CHUNK_FEAT) {
89            return handleFEAT(request);
90        } else {
91            throw new RuntimeException("Unknown packet "
92                + ChunkHandler.name(type));
93        }
94    }
95
96    /*
97     * Handle introductory packet.
98     */
99    private Chunk handleHELO(Chunk request) {
100        if (false)
101            return createFailChunk(123, "This is a test");
102
103        /*
104         * Process the request.
105         */
106        ByteBuffer in = wrapChunk(request);
107
108        int serverProtoVers = in.getInt();
109        if (false)
110            Log.v("ddm-hello", "Server version is " + serverProtoVers);
111
112        /*
113         * Create a response.
114         */
115        String vmName = System.getProperty("java.vm.name", "?");
116        String vmVersion = System.getProperty("java.vm.version", "?");
117        String vmIdent = vmName + " v" + vmVersion;
118
119        //String appName = android.app.ActivityThread.currentPackageName();
120        //if (appName == null)
121        //    appName = "unknown";
122        String appName = DdmHandleAppName.getAppName();
123
124        ByteBuffer out = ByteBuffer.allocate(20
125                            + vmIdent.length()*2 + appName.length()*2);
126        out.order(ChunkHandler.CHUNK_ORDER);
127        out.putInt(DdmServer.CLIENT_PROTOCOL_VERSION);
128        out.putInt(android.os.Process.myPid());
129        out.putInt(vmIdent.length());
130        out.putInt(appName.length());
131        putString(out, vmIdent);
132        putString(out, appName);
133        out.putInt(UserHandle.myUserId());
134
135        Chunk reply = new Chunk(CHUNK_HELO, out);
136
137        /*
138         * Take the opportunity to inform DDMS if we are waiting for a
139         * debugger to attach.
140         */
141        if (Debug.waitingForDebugger())
142            sendWAIT(0);
143
144        return reply;
145    }
146
147    /*
148     * Handle request for list of supported features.
149     */
150    private Chunk handleFEAT(Chunk request) {
151        // TODO: query the VM to ensure that support for these features
152        // is actually compiled in
153        final String[] vmFeatures = Debug.getVmFeatureList();
154
155        if (false)
156            Log.v("ddm-heap", "Got feature list request");
157
158        int size = 4 + 4 * (vmFeatures.length + NATIVE_FEATURES.length);
159        for (int i = vmFeatures.length-1; i >= 0; i--)
160            size += vmFeatures[i].length() * 2;
161        for (int i = NATIVE_FEATURES.length-1; i>= 0; i--)
162            size += NATIVE_FEATURES[i].length() * 2;
163
164        ByteBuffer out = ByteBuffer.allocate(size);
165        out.order(ChunkHandler.CHUNK_ORDER);
166        out.putInt(vmFeatures.length + NATIVE_FEATURES.length);
167        for (int i = vmFeatures.length-1; i >= 0; i--) {
168            out.putInt(vmFeatures[i].length());
169            putString(out, vmFeatures[i]);
170        }
171        for (int i = NATIVE_FEATURES.length-1; i >= 0; i--) {
172            out.putInt(NATIVE_FEATURES[i].length());
173            putString(out, NATIVE_FEATURES[i]);
174        }
175
176        return new Chunk(CHUNK_FEAT, out);
177    }
178
179    /**
180     * Send up a WAIT chunk.  The only currently defined value for "reason"
181     * is zero, which means "waiting for a debugger".
182     */
183    public static void sendWAIT(int reason) {
184        byte[] data = new byte[] { (byte) reason };
185        Chunk waitChunk = new Chunk(CHUNK_WAIT, data, 0, 1);
186        DdmServer.sendChunk(waitChunk);
187    }
188}
189
190