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 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      */
     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      */
     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      */
     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      */
     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      */
     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 */
    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      */
    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      */
    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