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 android.ddm; 18 19 import org.apache.harmony.dalvik.ddmc.Chunk; 20 import org.apache.harmony.dalvik.ddmc.ChunkHandler; 21 import org.apache.harmony.dalvik.ddmc.DdmServer; 22 import android.util.Log; 23 import android.os.Debug; 24 import android.os.UserHandle; 25 26 import java.nio.ByteBuffer; 27 28 /** 29 * Handle "hello" messages and feature discovery. 30 */ 31 public class DdmHandleHello extends ChunkHandler { 32 33 public static final int CHUNK_HELO = type("HELO"); 34 public static final int CHUNK_WAIT = type("WAIT"); 35 public static final int CHUNK_FEAT = type("FEAT"); 36 37 private static DdmHandleHello mInstance = new DdmHandleHello(); 38 39 40 /* singleton, do not instantiate */ DdmHandleHello()41 private DdmHandleHello() {} 42 43 /** 44 * Register for the messages we're interested in. 45 */ register()46 public static void register() { 47 DdmServer.registerHandler(CHUNK_HELO, mInstance); 48 DdmServer.registerHandler(CHUNK_FEAT, mInstance); 49 } 50 51 /** 52 * Called when the DDM server connects. The handler is allowed to 53 * send messages to the server. 54 */ connected()55 public void connected() { 56 if (false) 57 Log.v("ddm-hello", "Connected!"); 58 59 if (false) { 60 /* test spontaneous transmission */ 61 byte[] data = new byte[] { 0, 1, 2, 3, 4, -4, -3, -2, -1, 127 }; 62 Chunk testChunk = 63 new Chunk(ChunkHandler.type("TEST"), data, 1, data.length-2); 64 DdmServer.sendChunk(testChunk); 65 } 66 } 67 68 /** 69 * Called when the DDM server disconnects. Can be used to disable 70 * periodic transmissions or clean up saved state. 71 */ disconnected()72 public void disconnected() { 73 if (false) 74 Log.v("ddm-hello", "Disconnected!"); 75 } 76 77 /** 78 * Handle a chunk of data. 79 */ handleChunk(Chunk request)80 public Chunk handleChunk(Chunk request) { 81 if (false) 82 Log.v("ddm-heap", "Handling " + name(request.type) + " chunk"); 83 int type = request.type; 84 85 if (type == CHUNK_HELO) { 86 return handleHELO(request); 87 } else if (type == CHUNK_FEAT) { 88 return handleFEAT(request); 89 } else { 90 throw new RuntimeException("Unknown packet " 91 + ChunkHandler.name(type)); 92 } 93 } 94 95 /* 96 * Handle introductory packet. 97 */ handleHELO(Chunk request)98 private Chunk handleHELO(Chunk request) { 99 if (false) 100 return createFailChunk(123, "This is a test"); 101 102 /* 103 * Process the request. 104 */ 105 ByteBuffer in = wrapChunk(request); 106 107 int serverProtoVers = in.getInt(); 108 if (false) 109 Log.v("ddm-hello", "Server version is " + serverProtoVers); 110 111 /* 112 * Create a response. 113 */ 114 String vmName = System.getProperty("java.vm.name", "?"); 115 String vmVersion = System.getProperty("java.vm.version", "?"); 116 String vmIdent = vmName + " v" + vmVersion; 117 118 //String appName = android.app.ActivityThread.currentPackageName(); 119 //if (appName == null) 120 // appName = "unknown"; 121 String appName = DdmHandleAppName.getAppName(); 122 123 ByteBuffer out = ByteBuffer.allocate(20 124 + vmIdent.length()*2 + appName.length()*2); 125 out.order(ChunkHandler.CHUNK_ORDER); 126 out.putInt(DdmServer.CLIENT_PROTOCOL_VERSION); 127 out.putInt(android.os.Process.myPid()); 128 out.putInt(vmIdent.length()); 129 out.putInt(appName.length()); 130 putString(out, vmIdent); 131 putString(out, appName); 132 out.putInt(UserHandle.myUserId()); 133 134 Chunk reply = new Chunk(CHUNK_HELO, out); 135 136 /* 137 * Take the opportunity to inform DDMS if we are waiting for a 138 * debugger to attach. 139 */ 140 if (Debug.waitingForDebugger()) 141 sendWAIT(0); 142 143 return reply; 144 } 145 146 /* 147 * Handle request for list of supported features. 148 */ handleFEAT(Chunk request)149 private Chunk handleFEAT(Chunk request) { 150 // TODO: query the VM to ensure that support for these features 151 // is actually compiled in 152 final String[] features = Debug.getVmFeatureList(); 153 154 if (false) 155 Log.v("ddm-heap", "Got feature list request"); 156 157 int size = 4 + 4 * features.length; 158 for (int i = features.length-1; i >= 0; i--) 159 size += features[i].length() * 2; 160 161 ByteBuffer out = ByteBuffer.allocate(size); 162 out.order(ChunkHandler.CHUNK_ORDER); 163 out.putInt(features.length); 164 for (int i = features.length-1; i >= 0; i--) { 165 out.putInt(features[i].length()); 166 putString(out, features[i]); 167 } 168 169 return new Chunk(CHUNK_FEAT, out); 170 } 171 172 /** 173 * Send up a WAIT chunk. The only currently defined value for "reason" 174 * is zero, which means "waiting for a debugger". 175 */ sendWAIT(int reason)176 public static void sendWAIT(int reason) { 177 byte[] data = new byte[] { (byte) reason }; 178 Chunk waitChunk = new Chunk(CHUNK_WAIT, data, 0, 1); 179 DdmServer.sendChunk(waitChunk); 180 } 181 } 182 183