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. This is called during JNI_CreateJavaVM 101 * before frameworks native methods are registered, so be careful not 102 * to call any APIs that depend on frameworks native code. 103 */ 104 private Chunk handleHELO(Chunk request) { 105 if (false) 106 return createFailChunk(123, "This is a test"); 107 108 /* 109 * Process the request. 110 */ 111 ByteBuffer in = wrapChunk(request); 112 113 int serverProtoVers = in.getInt(); 114 if (false) 115 Log.v("ddm-hello", "Server version is " + serverProtoVers); 116 117 /* 118 * Create a response. 119 */ 120 String vmName = System.getProperty("java.vm.name", "?"); 121 String vmVersion = System.getProperty("java.vm.version", "?"); 122 String vmIdent = vmName + " v" + vmVersion; 123 124 //String appName = android.app.ActivityThread.currentPackageName(); 125 //if (appName == null) 126 // appName = "unknown"; 127 String appName = DdmHandleAppName.getAppName(); 128 129 ByteBuffer out = ByteBuffer.allocate(20 130 + vmIdent.length()*2 + appName.length()*2); 131 out.order(ChunkHandler.CHUNK_ORDER); 132 out.putInt(DdmServer.CLIENT_PROTOCOL_VERSION); 133 out.putInt(android.os.Process.myPid()); 134 out.putInt(vmIdent.length()); 135 out.putInt(appName.length()); 136 putString(out, vmIdent); 137 putString(out, appName); 138 out.putInt(UserHandle.myUserId()); 139 140 Chunk reply = new Chunk(CHUNK_HELO, out); 141 142 /* 143 * Take the opportunity to inform DDMS if we are waiting for a 144 * debugger to attach. 145 */ 146 if (Debug.waitingForDebugger()) 147 sendWAIT(0); 148 149 return reply; 150 } 151 152 /* 153 * Handle request for list of supported features. 154 */ 155 private Chunk handleFEAT(Chunk request) { 156 // TODO: query the VM to ensure that support for these features 157 // is actually compiled in 158 final String[] vmFeatures = Debug.getVmFeatureList(); 159 160 if (false) 161 Log.v("ddm-heap", "Got feature list request"); 162 163 int size = 4 + 4 * (vmFeatures.length + FRAMEWORK_FEATURES.length); 164 for (int i = vmFeatures.length-1; i >= 0; i--) 165 size += vmFeatures[i].length() * 2; 166 for (int i = FRAMEWORK_FEATURES.length-1; i>= 0; i--) 167 size += FRAMEWORK_FEATURES[i].length() * 2; 168 169 ByteBuffer out = ByteBuffer.allocate(size); 170 out.order(ChunkHandler.CHUNK_ORDER); 171 out.putInt(vmFeatures.length + FRAMEWORK_FEATURES.length); 172 for (int i = vmFeatures.length-1; i >= 0; i--) { 173 out.putInt(vmFeatures[i].length()); 174 putString(out, vmFeatures[i]); 175 } 176 for (int i = FRAMEWORK_FEATURES.length-1; i >= 0; i--) { 177 out.putInt(FRAMEWORK_FEATURES[i].length()); 178 putString(out, FRAMEWORK_FEATURES[i]); 179 } 180 181 return new Chunk(CHUNK_FEAT, out); 182 } 183 184 /** 185 * Send up a WAIT chunk. The only currently defined value for "reason" 186 * is zero, which means "waiting for a debugger". 187 */ 188 public static void sendWAIT(int reason) { 189 byte[] data = new byte[] { (byte) reason }; 190 Chunk waitChunk = new Chunk(CHUNK_WAIT, data, 0, 1); 191 DdmServer.sendChunk(waitChunk); 192 } 193 } 194 195