1 /******************************************************************************
2  *
3  *  Copyright (C) 2014 Google, Inc.
4  *
5  *  Licensed under the Apache License, Version 2.0 (the "License");
6  *  you may not use this file except in compliance with the License.
7  *  You may obtain a copy of the License at:
8  *
9  *  http://www.apache.org/licenses/LICENSE-2.0
10  *
11  *  Unless required by applicable law or agreed to in writing, software
12  *  distributed under the License is distributed on an "AS IS" BASIS,
13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *  See the License for the specific language governing permissions and
15  *  limitations under the License.
16  *
17  ******************************************************************************/
18 
19 #include <cutils/properties.h>
20 #include <pthread.h>
21 #include <stdlib.h>
22 #include <unistd.h>
23 
24 #include "base.h"
25 #include "btcore/include/bdaddr.h"
26 #include "cases/cases.h"
27 #include "osi/include/config.h"
28 #include "support/callbacks.h"
29 #include "support/hal.h"
30 #include "support/gatt.h"
31 #include "support/pan.h"
32 #include "support/rfcomm.h"
33 
34 // How long the watchdog thread should wait before checking if a test has completed.
35 // Any individual test will have at least WATCHDOG_PERIOD_SEC and at most
36 // 2 * WATCHDOG_PERIOD_SEC seconds to complete.
37 static const int WATCHDOG_PERIOD_SEC = 1 * 60;
38 static const char *CONFIG_FILE_PATH = "/data/misc/bluedroid/bt_config.conf";
39 
40 const bt_interface_t *bt_interface;
41 bt_bdaddr_t bt_remote_bdaddr;
42 
43 static pthread_t watchdog_thread;
44 static int watchdog_id;
45 static bool watchdog_running;
46 
watchdog_fn(void * arg)47 static void *watchdog_fn(void *arg) {
48   int current_id = 0;
49   for (;;) {
50     // Check every second whether this thread should exit and check
51     // every WATCHDOG_PERIOD_SEC whether we should terminate the process.
52     for (int i = 0; watchdog_running && i < WATCHDOG_PERIOD_SEC; ++i) {
53       sleep(1);
54     }
55 
56     if (!watchdog_running)
57       break;
58 
59     if (current_id == watchdog_id) {
60       printf("Watchdog detected hanging test suite, aborting...\n");
61       exit(-1);
62     }
63     current_id = watchdog_id;
64   }
65   return NULL;
66 }
67 
is_shell_running(void)68 static bool is_shell_running(void) {
69   char property_str[100];
70   property_get("init.svc.zygote", property_str, NULL);
71   if (!strcmp("running", property_str)) {
72     return true;
73   }
74   return false;
75 }
76 
print_usage(const char * program_name)77 static void print_usage(const char *program_name) {
78   printf("Usage: %s [options] [test name]\n", program_name);
79   printf("\n");
80   printf("Options:\n");
81   printf("  %-20sdisplay this help text.\n", "--help");
82   printf("  %-20sdo not run sanity suite.\n", "--insanity");
83   printf("\n");
84   printf("Valid test names are:\n");
85   for (size_t i = 0; i < sanity_suite_size; ++i) {
86     printf("  %s\n", sanity_suite[i].function_name);
87   }
88   for (size_t i = 0; i < test_suite_size; ++i) {
89     printf("  %s\n", test_suite[i].function_name);
90   }
91 }
92 
is_valid(const char * test_name)93 static bool is_valid(const char *test_name) {
94   for (size_t i = 0; i < sanity_suite_size; ++i) {
95     if (!strcmp(test_name, sanity_suite[i].function_name)) {
96       return true;
97     }
98   }
99   for (size_t i = 0; i < test_suite_size; ++i) {
100     if (!strcmp(test_name, test_suite[i].function_name)) {
101       return true;
102     }
103   }
104   return false;
105 }
106 
main(int argc,char ** argv)107 int main(int argc, char **argv) {
108   const char *test_name = NULL;
109   bool skip_sanity_suite = false;
110 
111   for (int i = 1; i < argc; ++i) {
112     if (!strcmp("--help", argv[i])) {
113       print_usage(argv[0]);
114       return 0;
115     }
116 
117     if (!strcmp("--insanity", argv[i])) {
118       skip_sanity_suite = true;
119       continue;
120     }
121 
122     if (!is_valid(argv[i])) {
123       printf("Error: invalid test name.\n");
124       print_usage(argv[0]);
125       return -1;
126     }
127 
128     if (test_name != NULL) {
129       printf("Error: invalid arguments.\n");
130       print_usage(argv[0]);
131       return -1;
132     }
133 
134     test_name = argv[i];
135   }
136 
137   if (is_shell_running()) {
138     printf("Run 'adb shell stop' before running %s.\n", argv[0]);
139     return -1;
140   }
141 
142   config_t *config = config_new(CONFIG_FILE_PATH);
143   if (!config) {
144     printf("Error: unable to open stack config file.\n");
145     print_usage(argv[0]);
146     return -1;
147   }
148 
149   for (const config_section_node_t *node = config_section_begin(config); node != config_section_end(config); node = config_section_next(node)) {
150     const char *name = config_section_name(node);
151     if (config_has_key(config, name, "LinkKey") && string_to_bdaddr(name, &bt_remote_bdaddr)) {
152       break;
153     }
154   }
155 
156   config_free(config);
157 
158   if (bdaddr_is_empty(&bt_remote_bdaddr)) {
159     printf("Error: unable to find paired device in config file.\n");
160     print_usage(argv[0]);
161     return -1;
162   }
163 
164   if (!hal_open(callbacks_get_adapter_struct())) {
165     printf("Unable to open Bluetooth HAL.\n");
166     return 1;
167   }
168 
169   if (!btsocket_init()) {
170     printf("Unable to initialize Bluetooth sockets.\n");
171     return 2;
172   }
173 
174   if (!pan_init()) {
175     printf("Unable to initialize PAN.\n");
176     return 3;
177   }
178 
179   if (!gatt_init()) {
180     printf("Unable to initialize GATT.\n");
181     return 4;
182   }
183 
184   watchdog_running = true;
185   pthread_create(&watchdog_thread, NULL, watchdog_fn, NULL);
186 
187   static const char *DEFAULT  = "\x1b[0m";
188   static const char *GREEN = "\x1b[0;32m";
189   static const char *RED   = "\x1b[0;31m";
190 
191   // If the output is not a TTY device, don't colorize output.
192   if (!isatty(fileno(stdout))) {
193     DEFAULT = GREEN = RED = "";
194   }
195 
196   int pass = 0;
197   int fail = 0;
198   int case_num = 0;
199 
200   // If test name is specified, run that specific test.
201   // Otherwise run through the sanity suite.
202   if (!skip_sanity_suite) {
203     for (size_t i = 0; i < sanity_suite_size; ++i) {
204       if (!test_name || !strcmp(test_name, sanity_suite[i].function_name)) {
205         callbacks_init();
206         if (sanity_suite[i].function()) {
207           printf("[%4d] %-64s [%sPASS%s]\n", ++case_num, sanity_suite[i].function_name, GREEN, DEFAULT);
208           ++pass;
209         } else {
210           printf("[%4d] %-64s [%sFAIL%s]\n", ++case_num, sanity_suite[i].function_name, RED, DEFAULT);
211           ++fail;
212         }
213         callbacks_cleanup();
214         ++watchdog_id;
215       }
216     }
217   }
218 
219   // If there was a failure in the sanity suite, don't bother running the rest of the tests.
220   if (fail) {
221     printf("\n%sSanity suite failed with %d errors.%s\n", RED, fail, DEFAULT);
222     hal_close();
223     return 4;
224   }
225 
226   // If test name is specified, run that specific test.
227   // Otherwise run through the full test suite.
228   for (size_t i = 0; i < test_suite_size; ++i) {
229     if (!test_name || !strcmp(test_name, test_suite[i].function_name)) {
230       callbacks_init();
231       CALL_AND_WAIT(bt_interface->enable(), adapter_state_changed);
232       if (test_suite[i].function()) {
233         printf("[%4d] %-64s [%sPASS%s]\n", ++case_num, test_suite[i].function_name, GREEN, DEFAULT);
234         ++pass;
235       } else {
236         printf("[%4d] %-64s [%sFAIL%s]\n", ++case_num, test_suite[i].function_name, RED, DEFAULT);
237         ++fail;
238       }
239       CALL_AND_WAIT(bt_interface->disable(), adapter_state_changed);
240       callbacks_cleanup();
241       ++watchdog_id;
242     }
243   }
244 
245   printf("\n");
246 
247   if (fail) {
248     printf("%d/%d tests failed. See above for failed test cases.\n", fail, sanity_suite_size + test_suite_size);
249   } else {
250     printf("All tests passed!\n");
251   }
252 
253   watchdog_running = false;
254   pthread_join(watchdog_thread, NULL);
255 
256   hal_close();
257 
258   return 0;
259 }
260