1adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/*
2adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Copyright (C) 2007 The Android Open Source Project
3adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *
4adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
5adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * you may not use this file except in compliance with the License.
6adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * You may obtain a copy of the License at
7adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *
8adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
9adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *
10adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Unless required by applicable law or agreed to in writing, software
11adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
12adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * See the License for the specific language governing permissions and
14adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * limitations under the License.
15adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */
16adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
17adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectpackage org.apache.harmony.dalvik.ddmc;
18adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
19adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.util.Collection;
20adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.util.HashMap;
21adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.util.Iterator;
22adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
23adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
24adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/**
25adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * This represents our connection to the DDM Server.
26adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */
27adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectpublic class DdmServer {
28adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
29adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public static final int CLIENT_PROTOCOL_VERSION = 1;
30adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
31adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private static HashMap<Integer,ChunkHandler> mHandlerMap =
32adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        new HashMap<Integer,ChunkHandler>();
33adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
34adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private static final int CONNECTED = 1;
35adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private static final int DISCONNECTED = 2;
36adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
37adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private static volatile boolean mRegistrationComplete = false;
38adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private static boolean mRegistrationTimedOut = false;
39adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
40adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
41adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
42adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Don't instantiate; all members and methods are static.
43adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
44adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private DdmServer() {}
45adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
46adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
47adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Register an instance of the ChunkHandler class to handle a specific
48adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * chunk type.
49adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *
50adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Throws an exception if the type already has a handler registered.
51adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
52adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public static void registerHandler(int type, ChunkHandler handler) {
53c2d0a1f1bd2c6414c29dd44fe240dcf1f45e59b9Elliott Hughes        if (handler == null) {
54c2d0a1f1bd2c6414c29dd44fe240dcf1f45e59b9Elliott Hughes            throw new NullPointerException("handler == null");
55c2d0a1f1bd2c6414c29dd44fe240dcf1f45e59b9Elliott Hughes        }
56adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        synchronized (mHandlerMap) {
57adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (mHandlerMap.get(type) != null)
58adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                throw new RuntimeException("type " + Integer.toHexString(type)
59adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    + " already registered");
60adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
61adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            mHandlerMap.put(type, handler);
62adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
63adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
64adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
65adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
66adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Unregister the existing handler for the specified type.
67adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *
68adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Returns the old handler.
69adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
70adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public static ChunkHandler unregisterHandler(int type) {
71adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        synchronized (mHandlerMap) {
72adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return mHandlerMap.remove(type);
73adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
74adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
75adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
76adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
77adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * The application must call here after it finishes registering
78adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * handlers.
79adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
80adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public static void registrationComplete() {
81adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // sync on mHandlerMap because it's convenient and makes a kind of
82adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // sense
83adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        synchronized (mHandlerMap) {
84adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            mRegistrationComplete = true;
85adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            mHandlerMap.notifyAll();
86adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
87adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
88adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
89adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
90adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Send a chunk of data to the DDM server.  This takes the form of a
91adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * JDWP "event", which does not elicit a response from the server.
92adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *
93adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Use this for "unsolicited" chunks.
94adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
95adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public static void sendChunk(Chunk chunk) {
96adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        nativeSendChunk(chunk.type, chunk.data, chunk.offset, chunk.length);
97adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
98adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
99adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /* send a chunk to the DDM server */
100adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    native private static void nativeSendChunk(int type, byte[] data,
101adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        int offset, int length);
102adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
103adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /*
104adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Called by the VM when the DDM server connects or disconnects.
105adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
106adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private static void broadcast(int event)
107adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    {
108adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        synchronized (mHandlerMap) {
109adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            Collection values = mHandlerMap.values();
110adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            Iterator iter = values.iterator();
111adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
112adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            while (iter.hasNext()) {
113adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                ChunkHandler handler = (ChunkHandler) iter.next();
114adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                switch (event) {
115adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    case CONNECTED:
116adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        handler.connected();
117adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        break;
118adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    case DISCONNECTED:
119adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        handler.disconnected();
120adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        break;
121adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    default:
122adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        throw new UnsupportedOperationException();
123adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
124adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
125adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
126adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
127adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
128adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /*
129adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * This is called by the VM when a chunk arrives.
130adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *
131adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * For a DDM-aware application, we want to wait until the app has had
132adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * a chance to register all of its chunk handlers.  Otherwise, we'll
133adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * end up dropping early-arriving packets on the floor.
134adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *
135adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * For a non-DDM-aware application, we'll end up waiting here forever
136adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * if DDMS happens to connect.  It's hard to know for sure that
137adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * registration isn't going to happen, so we settle for a timeout.
138adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
139adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private static Chunk dispatch(int type, byte[] data, int offset, int length)
140adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    {
141adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        ChunkHandler handler;
142adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
143adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        synchronized (mHandlerMap) {
144adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            /*
145adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project             * If registration hasn't completed, and we haven't timed out
146adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project             * waiting for it, wait a bit.
147adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project             */
148adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            while (!mRegistrationComplete && !mRegistrationTimedOut) {
149adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                //System.out.println("dispatch() waiting for reg");
150adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                try {
151adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    mHandlerMap.wait(1000);     // 1.0 sec
152adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                } catch (InterruptedException ie) {
153adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    continue;
154adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
155adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
156adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                if (!mRegistrationComplete) {
157adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    /* timed out, don't wait again */
158adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    mRegistrationTimedOut = true;
159adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
160adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
161adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
162adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            handler = mHandlerMap.get(type);
163adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
164adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        //System.out.println(" dispatch cont");
165adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
166adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (handler == null) {
167adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return null;
168adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
169adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
170adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        Chunk chunk = new Chunk(type, data, offset, length);
171adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return handler.handleChunk(chunk);
172adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
173adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project}
174