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