1 /* 2 * Copyright (C) 2013 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 com.android.bluetooth.gatt; 18 19 import android.content.Intent; 20 import android.os.Bundle; 21 import android.util.Log; 22 import java.util.UUID; 23 24 /** 25 * Helper class containing useful tools for GATT service debugging. 26 */ 27 /*package*/ class GattDebugUtils { 28 private static final String TAG = GattServiceConfig.TAG_PREFIX + "DebugUtils"; 29 private static final boolean DEBUG_ADMIN = GattServiceConfig.DEBUG_ADMIN; 30 31 private static final String ACTION_DEBUG_DUMP_CLIENTMAP = 32 "android.bluetooth.action.DEBUG_DUMP_CLIENTMAP"; 33 private static final String ACTION_DEBUG_DUMP_SERVERMAP = 34 "android.bluetooth.action.DEBUG_DUMP_SERVERMAP"; 35 private static final String ACTION_DEBUG_DUMP_HANDLEMAP = 36 "android.bluetooth.action.DEBUG_DUMP_HANDLEMAP"; 37 38 private static final String ACTION_GATT_PAIRING_CONFIG = 39 "android.bluetooth.action.GATT_PAIRING_CONFIG"; 40 41 private static final String ACTION_GATT_TEST_USAGE = 42 "android.bluetooth.action.GATT_TEST_USAGE"; 43 private static final String ACTION_GATT_TEST_ENABLE = 44 "android.bluetooth.action.GATT_TEST_ENABLE"; 45 private static final String ACTION_GATT_TEST_CONNECT = 46 "android.bluetooth.action.GATT_TEST_CONNECT"; 47 private static final String ACTION_GATT_TEST_DISCONNECT = 48 "android.bluetooth.action.GATT_TEST_DISCONNECT"; 49 private static final String ACTION_GATT_TEST_DISCOVER = 50 "android.bluetooth.action.GATT_TEST_DISCOVER"; 51 52 private static final String EXTRA_ENABLE = "enable"; 53 private static final String EXTRA_ADDRESS = "address"; 54 private static final String EXTRA_UUID = "uuid"; 55 private static final String EXTRA_TYPE = "type"; 56 private static final String EXTRA_ADDR_TYPE = "addr_type"; 57 private static final String EXTRA_SHANDLE = "start"; 58 private static final String EXTRA_EHANDLE = "end"; 59 private static final String EXTRA_AUTH_REQ = "auth_req"; 60 private static final String EXTRA_IO_CAP = "io_cap"; 61 private static final String EXTRA_INIT_KEY = "init_key"; 62 private static final String EXTRA_RESP_KEY = "resp_key"; 63 private static final String EXTRA_MAX_KEY = "max_key"; 64 65 /** 66 * Handles intents passed in via GattService.onStartCommand(). 67 * This allows sending debug actions to the running service. 68 * To trigger a debug action, invoke the following shell command: 69 * 70 * adb shell am startservice -a <action> <component> 71 * 72 * Where <action> represents one of the ACTION_* constants defines above 73 * and <component> identifies the GATT service. 74 * 75 * For example: 76 * import com.android.bluetooth.gatt.GattService; 77 */ 78 static boolean handleDebugAction(GattService svc, Intent intent) { 79 if (!DEBUG_ADMIN) return false; 80 81 String action = intent.getAction(); 82 Log.d(TAG, "handleDebugAction() action=" + action); 83 84 /* 85 * Debug log functinos 86 */ 87 88 if (ACTION_DEBUG_DUMP_CLIENTMAP.equals(action)) { 89 svc.mClientMap.dump(); 90 91 } else if (ACTION_DEBUG_DUMP_SERVERMAP.equals(action)) { 92 svc.mServerMap.dump(); 93 94 } else if (ACTION_DEBUG_DUMP_HANDLEMAP.equals(action)) { 95 svc.mHandleMap.dump(); 96 97 /* 98 * PTS test commands 99 */ 100 101 } else if (ACTION_GATT_TEST_USAGE.equals(action)) { 102 logUsageInfo(); 103 104 } else if (ACTION_GATT_TEST_ENABLE.equals(action)) { 105 boolean bEnable = intent.getBooleanExtra(EXTRA_ENABLE, true); 106 svc.gattTestCommand( 0x01, null,null, bEnable ? 1 : 0, 0,0,0,0); 107 108 } else if (ACTION_GATT_TEST_CONNECT.equals(action)) { 109 String address = intent.getStringExtra(EXTRA_ADDRESS); 110 int type = intent.getIntExtra(EXTRA_TYPE, 2 /* LE device */); 111 int addr_type = intent.getIntExtra(EXTRA_ADDR_TYPE, 0 /* Static */); 112 svc.gattTestCommand( 0x02, null, address, type, addr_type, 0,0,0); 113 114 } else if (ACTION_GATT_TEST_DISCONNECT.equals(action)) { 115 svc.gattTestCommand( 0x03, null, null, 0,0,0,0,0); 116 117 } else if (ACTION_GATT_TEST_DISCOVER.equals(action)) { 118 UUID uuid = getUuidExtra(intent); 119 int type = intent.getIntExtra(EXTRA_TYPE, 1 /* All services */); 120 int shdl = getHandleExtra(intent, EXTRA_SHANDLE, 1); 121 int ehdl = getHandleExtra(intent, EXTRA_EHANDLE, 0xFFFF); 122 svc.gattTestCommand( 0x04, uuid, null, type, shdl, ehdl, 0,0); 123 124 } else if (ACTION_GATT_PAIRING_CONFIG.equals(action)) { 125 int auth_req = intent.getIntExtra(EXTRA_AUTH_REQ, 5); 126 int io_cap = intent.getIntExtra(EXTRA_IO_CAP, 4); 127 int init_key = intent.getIntExtra(EXTRA_INIT_KEY, 7); 128 int resp_key = intent.getIntExtra(EXTRA_RESP_KEY, 7); 129 int max_key = intent.getIntExtra(EXTRA_MAX_KEY, 16); 130 svc.gattTestCommand( 0xF0, null, null, auth_req, io_cap, init_key, 131 resp_key, max_key); 132 133 } else { 134 return false; 135 } 136 137 return true; 138 } 139 140 /** 141 * Attempts to retrieve an extra from an intent first as hex value, 142 * then as an ineger. 143 * @hide 144 */ 145 static private int getHandleExtra(Intent intent, String extra, int default_value) { 146 Bundle extras = intent.getExtras(); 147 Object uuid = extras != null ? extras.get(extra) : null; 148 if (uuid != null && uuid.getClass().getName().equals("java.lang.String")) { 149 try 150 { 151 return Integer.parseInt(extras.getString(extra), 16); 152 } catch (NumberFormatException e) { 153 return default_value; 154 } 155 } 156 157 return intent.getIntExtra(extra, default_value); 158 } 159 160 /** 161 * Retrieves the EXTRA_UUID parameter. 162 * If a string of length 4 is detected, a 16-bit hex UUID is assumed and 163 * the default Bluetooth UUID is appended. 164 * @hide 165 */ 166 static private UUID getUuidExtra(Intent intent) { 167 String uuidStr = intent.getStringExtra(EXTRA_UUID); 168 if (uuidStr != null && uuidStr.length() == 4) { 169 uuidStr = String.format("0000%s-0000-1000-8000-00805f9b34fb", uuidStr); 170 } 171 return (uuidStr != null) ? UUID.fromString(uuidStr) : null; 172 } 173 174 /** 175 * Log usage information. 176 * @hide 177 */ 178 static private void logUsageInfo() { 179 StringBuilder b = new StringBuilder(); 180 b.append( "------------ GATT TEST ACTIONS ----------------"); 181 b.append("\nGATT_TEST_ENABLE"); 182 b.append("\n [--ez enable <bool>] Enable or disable,"); 183 b.append("\n defaults to true (enable).\n"); 184 b.append("\nGATT_TEST_CONNECT"); 185 b.append("\n --es address <bda>"); 186 b.append("\n [--ei addr_type <type>] Possible values:"); 187 b.append("\n 0 = Static (default)"); 188 b.append("\n 1 = Random\n"); 189 b.append("\n [--ei type <type>] Default is 2 (LE Only)\n"); 190 b.append("\nGATT_TEST_DISCONNECT\n"); 191 b.append("\nGATT_TEST_DISCOVER"); 192 b.append("\n [--ei type <type>] Possible values:"); 193 b.append("\n 1 = Discover all services (default)"); 194 b.append("\n 2 = Discover services by UUID"); 195 b.append("\n 3 = Discover included services"); 196 b.append("\n 4 = Discover characteristics"); 197 b.append("\n 5 = Discover descriptors\n"); 198 b.append("\n [--es uuid <uuid>] Optional; Can be either full 128-bit"); 199 b.append("\n UUID hex string, or 4 hex characters"); 200 b.append("\n for 16-bit UUIDs.\n"); 201 b.append("\n [--ei start <hdl>] Start of handle range (default 1)"); 202 b.append("\n [--ei end <hdl>] End of handle range (default 65355)"); 203 b.append("\n or"); 204 b.append("\n [--es start <hdl>] Start of handle range (hex format)"); 205 b.append("\n [--es end <hdl>] End of handle range (hex format)\n"); 206 b.append("\nGATT_PAIRING_CONFIG"); 207 b.append("\n [--ei auth_req] Authentication flag (default 5)"); 208 b.append("\n [--ei io_cap] IO capabilities (default 4)"); 209 b.append("\n [--ei init_key] Initial key size (default 7)"); 210 b.append("\n [--ei resp_key] Response key size (default 7)"); 211 b.append("\n [--ei max_key] Maximum key size (default 16)"); 212 b.append("\n------------------------------------------------"); 213 Log.i(TAG, b.toString()); 214 } 215 } 216