1 /*
2  * Copyright 2020 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 #define LOG_TAG "bt_headless"
18 
19 #include <bluetooth/log.h>
20 #include <fcntl.h>
21 #include <sys/socket.h>
22 #include <sys/wait.h>
23 #include <unistd.h>
24 
25 #include <iostream>
26 #include <unordered_map>
27 
28 #include "os/log.h"           // android log only
29 #include "test/headless/adapter/adapter.h"
30 #include "test/headless/connect/connect.h"
31 #include "test/headless/discovery/discovery.h"
32 #include "test/headless/dumpsys/dumpsys.h"
33 #include "test/headless/get_options.h"
34 #include "test/headless/headless.h"
35 #include "test/headless/log.h"
36 #include "test/headless/mode/mode.h"
37 #include "test/headless/nop/nop.h"
38 #include "test/headless/pairing/pairing.h"
39 #include "test/headless/read/read.h"
40 #include "test/headless/scan/scan.h"
41 #include "test/headless/sdp/sdp.h"
42 #include "test/headless/util.h"
43 
44 using namespace bluetooth::test::headless;
45 using namespace bluetooth;
46 
47 int console_fd = -1;
48 
49 namespace {
50 
51 constexpr char kRedirectedStderrFilename[] = "/dev/null";
52 FILE* redirected_stderr_{nullptr};
53 
54 // Ok...so if `stderr` stream is closed, the Android logging system will find
55 // another stream to write `LOG(<LogLevel>)` messages...any...stream.
56 // Unfortunately the next stream/fd is the bluetooth snooplog output
57 // file, so then a btsnoop_hci.log will interleave both raw hci packet
58 // data and Android LOG files preventing proper capture of hci traffic.
59 // To mitigate this, the `stderr` stream is redirected to another user
60 // provided stream, may be `/dev/null`, may be any file if so desired.
61 // This keeps everybody happy.
start_trick_the_android_logging_subsystem()62 void start_trick_the_android_logging_subsystem() {
63   redirected_stderr_ = freopen(kRedirectedStderrFilename, "w", stderr);
64   log::assert_that(redirected_stderr_ != nullptr,
65                    "Unable to open redirected stderr file");
66 }
67 
stop_trick_the_android_logging_subsystem()68 void stop_trick_the_android_logging_subsystem() {
69   log::assert_that(redirected_stderr_ != nullptr,
70                    "assert failed: redirected_stderr_ != nullptr");
71   fclose(redirected_stderr_);
72   redirected_stderr_ = nullptr;
73 }
74 
clear_logcat()75 void clear_logcat() {
76   int pid;
77   if ((pid = fork())) {
78     // parent process
79     int status;
80     waitpid(pid, &status, 0);  // wait for the child to exit
81     log::assert_that(WIFEXITED(status), "Unable to clear logcat");
82   } else {
83     // child process
84     const char exec[] = "/system/bin/logcat";
85     const char arg0[] = "-c";
86 
87     execl(exec, exec, arg0, NULL);
88 
89     log::fatal("Should not return from exec process");
90   }
91 }
92 
93 class Main : public HeadlessTest<int> {
94  public:
Main(const bluetooth::test::headless::GetOpt & options)95   Main(const bluetooth::test::headless::GetOpt& options)
96       : HeadlessTest<int>(options) {
97     test_nodes_.emplace(
98         "adapter",
99         std::make_unique<bluetooth::test::headless::Adapter>(options));
100     test_nodes_.emplace(
101         "dumpsys",
102         std::make_unique<bluetooth::test::headless::Dumpsys>(options));
103     test_nodes_.emplace(
104         "connect",
105         std::make_unique<bluetooth::test::headless::Connect>(options));
106     test_nodes_.emplace(
107         "mode", std::make_unique<bluetooth::test::headless::Mode>(options));
108     test_nodes_.emplace(
109         "nop", std::make_unique<bluetooth::test::headless::Nop>(options));
110     test_nodes_.emplace(
111         "pairing",
112         std::make_unique<bluetooth::test::headless::Pairing>(options));
113     test_nodes_.emplace(
114         "read", std::make_unique<bluetooth::test::headless::Read>(options));
115     test_nodes_.emplace(
116         "scan", std::make_unique<bluetooth::test::headless::Scan>(options));
117     test_nodes_.emplace(
118         "sdp", std::make_unique<bluetooth::test::headless::Sdp>(options));
119     test_nodes_.emplace(
120         "discovery",
121         std::make_unique<bluetooth::test::headless::Discovery>(options));
122   }
123 
Run()124   int Run() override {
125     console_fd = fcntl(STDERR_FILENO, F_DUPFD_CLOEXEC, STDERR_FILENO);
126     log::assert_that(console_fd != -1, "assert failed: console_fd != -1");
127     if (options_.close_stderr_) {
128       fclose(stderr);
129     }
130 
131     if (options_.clear_logcat_) {
132       clear_logcat();
133     }
134 
135     start_trick_the_android_logging_subsystem();
136     if (is_android_running()) {
137       LOG_CONSOLE("Android must be shutdown for binary to run");
138       LOG_CONSOLE("     /system/bin/stop");
139       return -1;
140     }
141     LOG_CONSOLE("bt_headless version:\'%s\'", build_id().c_str());
142     int rc = HeadlessTest<int>::Run();
143     stop_trick_the_android_logging_subsystem();
144     return rc;
145   }
146 };
147 
148 }  // namespace
149 
main(int argc,char ** argv)150 int main(int argc, char** argv) {
151   fflush(nullptr);
152   setvbuf(stdout, nullptr, _IOLBF, 0);
153 
154   bluetooth::test::headless::GetOpt options(argc, argv);
155   if (!options.IsValid()) {
156     return -1;
157   }
158 
159   Main main(options);
160   return main.Run();
161 }
162