Home | History | Annotate | Download | only in ddmc
      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