| /* |
| * Copyright (C) 2007 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package org.apache.harmony.dalvik.ddmc; |
| |
| import java.util.Collection; |
| import java.util.HashMap; |
| import java.util.Iterator; |
| |
| |
| /** |
| * This represents our connection to the DDM Server. |
| */ |
| public class DdmServer { |
| |
| public static final int CLIENT_PROTOCOL_VERSION = 1; |
| |
| private static HashMap<Integer,ChunkHandler> mHandlerMap = |
| new HashMap<Integer,ChunkHandler>(); |
| |
| private static final int CONNECTED = 1; |
| private static final int DISCONNECTED = 2; |
| |
| private static volatile boolean mRegistrationComplete = false; |
| private static boolean mRegistrationTimedOut = false; |
| |
| |
| /** |
| * Don't instantiate; all members and methods are static. |
| */ |
| private DdmServer() {} |
| |
| /** |
| * Register an instance of the ChunkHandler class to handle a specific |
| * chunk type. |
| * |
| * Throws an exception if the type already has a handler registered. |
| */ |
| public static void registerHandler(int type, ChunkHandler handler) { |
| if (handler == null) |
| throw new NullPointerException(); |
| |
| synchronized (mHandlerMap) { |
| if (mHandlerMap.get(type) != null) |
| throw new RuntimeException("type " + Integer.toHexString(type) |
| + " already registered"); |
| |
| mHandlerMap.put(type, handler); |
| } |
| } |
| |
| /** |
| * Unregister the existing handler for the specified type. |
| * |
| * Returns the old handler. |
| */ |
| public static ChunkHandler unregisterHandler(int type) { |
| synchronized (mHandlerMap) { |
| return mHandlerMap.remove(type); |
| } |
| } |
| |
| /** |
| * The application must call here after it finishes registering |
| * handlers. |
| */ |
| public static void registrationComplete() { |
| // sync on mHandlerMap because it's convenient and makes a kind of |
| // sense |
| synchronized (mHandlerMap) { |
| mRegistrationComplete = true; |
| mHandlerMap.notifyAll(); |
| } |
| } |
| |
| /** |
| * Send a chunk of data to the DDM server. This takes the form of a |
| * JDWP "event", which does not elicit a response from the server. |
| * |
| * Use this for "unsolicited" chunks. |
| */ |
| public static void sendChunk(Chunk chunk) { |
| nativeSendChunk(chunk.type, chunk.data, chunk.offset, chunk.length); |
| } |
| |
| /* send a chunk to the DDM server */ |
| native private static void nativeSendChunk(int type, byte[] data, |
| int offset, int length); |
| |
| /* |
| * Called by the VM when the DDM server connects or disconnects. |
| */ |
| private static void broadcast(int event) |
| { |
| synchronized (mHandlerMap) { |
| Collection values = mHandlerMap.values(); |
| Iterator iter = values.iterator(); |
| |
| while (iter.hasNext()) { |
| ChunkHandler handler = (ChunkHandler) iter.next(); |
| switch (event) { |
| case CONNECTED: |
| handler.connected(); |
| break; |
| case DISCONNECTED: |
| handler.disconnected(); |
| break; |
| default: |
| throw new UnsupportedOperationException(); |
| } |
| } |
| } |
| } |
| |
| /* |
| * This is called by the VM when a chunk arrives. |
| * |
| * For a DDM-aware application, we want to wait until the app has had |
| * a chance to register all of its chunk handlers. Otherwise, we'll |
| * end up dropping early-arriving packets on the floor. |
| * |
| * For a non-DDM-aware application, we'll end up waiting here forever |
| * if DDMS happens to connect. It's hard to know for sure that |
| * registration isn't going to happen, so we settle for a timeout. |
| */ |
| private static Chunk dispatch(int type, byte[] data, int offset, int length) |
| { |
| ChunkHandler handler; |
| |
| synchronized (mHandlerMap) { |
| /* |
| * If registration hasn't completed, and we haven't timed out |
| * waiting for it, wait a bit. |
| */ |
| while (!mRegistrationComplete && !mRegistrationTimedOut) { |
| //System.out.println("dispatch() waiting for reg"); |
| try { |
| mHandlerMap.wait(1000); // 1.0 sec |
| } catch (InterruptedException ie) { |
| continue; |
| } |
| |
| if (!mRegistrationComplete) { |
| /* timed out, don't wait again */ |
| mRegistrationTimedOut = true; |
| } |
| } |
| |
| handler = mHandlerMap.get(type); |
| } |
| //System.out.println(" dispatch cont"); |
| |
| if (handler == null) { |
| return null; |
| } |
| |
| Chunk chunk = new Chunk(type, data, offset, length); |
| return handler.handleChunk(chunk); |
| } |
| } |
| |