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