content: /*
   * Copyright (C) 2009 The Android Open Source Project
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *      http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  package android.ddm;
  
  import org.apache.harmony.dalvik.ddmc.Chunk;
  import org.apache.harmony.dalvik.ddmc.ChunkHandler;
  import org.apache.harmony.dalvik.ddmc.DdmServer;
  import android.os.Debug;
  import android.util.Log;
  import java.nio.ByteBuffer;
  
  /**
   * Handle profiling requests.
   */
  public class DdmHandleProfiling extends ChunkHandler {
  
      public static final int CHUNK_MPRS = type("MPRS");
      public static final int CHUNK_MPRE = type("MPRE");
      public static final int CHUNK_MPSS = type("MPSS");
      public static final int CHUNK_MPSE = type("MPSE");
      public static final int CHUNK_MPRQ = type("MPRQ");
      public static final int CHUNK_SPSS = type("SPSS");
      public static final int CHUNK_SPSE = type("SPSE");
  
      private static final boolean DEBUG = false;
      private static DdmHandleProfiling mInstance = new DdmHandleProfiling();
  
  
      /* singleton, do not instantiate */
      private DdmHandleProfiling() {}
  
      /**
       * Register for the messages we're interested in.
       */
      public static void register() {
          DdmServer.registerHandler(CHUNK_MPRS, mInstance);
          DdmServer.registerHandler(CHUNK_MPRE, mInstance);
          DdmServer.registerHandler(CHUNK_MPSS, mInstance);
          DdmServer.registerHandler(CHUNK_MPSE, mInstance);
          DdmServer.registerHandler(CHUNK_MPRQ, mInstance);
          DdmServer.registerHandler(CHUNK_SPSS, mInstance);
          DdmServer.registerHandler(CHUNK_SPSE, mInstance);
      }
  
      /**
       * Called when the DDM server connects.  The handler is allowed to
       * send messages to the server.
       */
      public void connected() {}
  
      /**
       * Called when the DDM server disconnects.  Can be used to disable
       * periodic transmissions or clean up saved state.
       */
      public void disconnected() {}
  
      /**
       * Handle a chunk of data.
       */
      public Chunk handleChunk(Chunk request) {
          if (DEBUG)
              Log.v("ddm-heap", "Handling " + name(request.type) + " chunk");
          int type = request.type;
  
          if (type == CHUNK_MPRS) {
              return handleMPRS(request);
          } else if (type == CHUNK_MPRE) {
              return handleMPRE(request);
          } else if (type == CHUNK_MPSS) {
              return handleMPSS(request);
          } else if (type == CHUNK_MPSE) {
              return handleMPSEOrSPSE(request, "Method");
          } else if (type == CHUNK_MPRQ) {
              return handleMPRQ(request);
          } else if (type == CHUNK_SPSS) {
              return handleSPSS(request);
          } else if (type == CHUNK_SPSE) {
              return handleMPSEOrSPSE(request, "Sample");
          } else {
              throw new RuntimeException("Unknown packet "
                  + ChunkHandler.name(type));
          }
      }
  
      /*
       * Handle a "Method PRofiling Start" request.
       */
      private Chunk handleMPRS(Chunk request) {
          ByteBuffer in = wrapChunk(request);
  
          int bufferSize = in.getInt();
          int flags = in.getInt();
          int len = in.getInt();
          String fileName = getString(in, len);
          if (DEBUG)
              Log.v("ddm-heap", "Method profiling start: filename='" + fileName
                  + "', size=" + bufferSize + ", flags=" + flags);
  
          try {
              Debug.startMethodTracing(fileName, bufferSize, flags);
              return null;        // empty response
          } catch (RuntimeException re) {
              return createFailChunk(1, re.getMessage());
          }
      }
  
      /*
       * Handle a "Method PRofiling End" request.
       */
      private Chunk handleMPRE(Chunk request) {
          byte result;
  
          try {
              Debug.stopMethodTracing();
              result = 0;
          } catch (RuntimeException re) {
              Log.w("ddm-heap", "Method profiling end failed: "
                  + re.getMessage());
              result = 1;
          }
  
          /* create a non-empty reply so the handler fires on completion */
          byte[] reply = { result };
          return new Chunk(CHUNK_MPRE, reply, 0, reply.length);
      }
  
      /*
       * Handle a "Method Profiling w/Streaming Start" request.
       */
      private Chunk handleMPSS(Chunk request) {
          ByteBuffer in = wrapChunk(request);
  
          int bufferSize = in.getInt();
          int flags = in.getInt();
          if (DEBUG) {
              Log.v("ddm-heap", "Method prof stream start: size=" + bufferSize
                  + ", flags=" + flags);
          }
  
          try {
              Debug.startMethodTracingDdms(bufferSize, flags, false, 0);
              return null;        // empty response
          } catch (RuntimeException re) {
              return createFailChunk(1, re.getMessage());
          }
      }
  
      /*
       * Handle a "Method Profiling w/Streaming End" request or a
       * "Sample Profiling w/Streaming End" request.
       */
      private Chunk handleMPSEOrSPSE(Chunk request, String type) {
          if (DEBUG) {
              Log.v("ddm-heap", type + " prof stream end");
          }
  
          try {
              Debug.stopMethodTracing();
          } catch (RuntimeException re) {
              Log.w("ddm-heap", type + " prof stream end failed: "
                  + re.getMessage());
              return createFailChunk(1, re.getMessage());
          }
  
          /* VM sent the (perhaps very large) response directly */
          return null;
      }
  
      /*
       * Handle a "Method PRofiling Query" request.
       */
      private Chunk handleMPRQ(Chunk request) {
          int result = Debug.getMethodTracingMode();
  
          /* create a non-empty reply so the handler fires on completion */
          byte[] reply = { (byte) result };
          return new Chunk(CHUNK_MPRQ, reply, 0, reply.length);
      }
  
      /*
       * Handle a "Sample Profiling w/Streaming Start" request.
       */
      private Chunk handleSPSS(Chunk request) {
          ByteBuffer in = wrapChunk(request);
  
          int bufferSize = in.getInt();
          int flags = in.getInt();
          int interval = in.getInt();
          if (DEBUG) {
              Log.v("ddm-heap", "Sample prof stream start: size=" + bufferSize
                  + ", flags=" + flags + ", interval=" + interval);
          }
  
          try {
              Debug.startMethodTracingDdms(bufferSize, flags, true, interval);
              return null;        // empty response
          } catch (RuntimeException re) {
              return createFailChunk(1, re.getMessage());
          }
      }
  }
  
  