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