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