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