1 /*
2 * Copyright (C) 2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15 #ifndef LOG_TAG
16 #define LOG_TAG "bt_fwk_switch_module"
17 #endif
18
19 #include "bluetooth_switch_module.h"
20
21 #include <algorithm>
22 #include "bluetooth_errorcode.h"
23 #include "bluetooth_log.h"
24
25 namespace OHOS {
26 namespace Bluetooth {
ToString(BluetoothSwitchEvent event)27 static const char *ToString(BluetoothSwitchEvent event)
28 {
29 switch (event) {
30 case BluetoothSwitchEvent::ENABLE_BLUETOOTH: return "ENABLE_BLUETOOTH";
31 case BluetoothSwitchEvent::DISABLE_BLUETOOTH: return "DISABLE_BLUETOOTH";
32 case BluetoothSwitchEvent::ENABLE_BLUETOOTH_TO_RESTRICE_MODE: return "ENABLE_BLUETOOTH_TO_RESTRICE_MODE";
33 case BluetoothSwitchEvent::BLUETOOTH_ON: return "BLUETOOTH_ON";
34 case BluetoothSwitchEvent::BLUETOOTH_OFF: return "BLUETOOTH_OFF";
35 case BluetoothSwitchEvent::BLUETOOTH_HALF: return "BLUETOOTH_HALF";
36 default: break;
37 }
38 return "Unknown";
39 }
40
LogBluetoothSwitchEvent(BluetoothSwitchEvent event)41 void BluetoothSwitchModule::LogBluetoothSwitchEvent(BluetoothSwitchEvent event)
42 {
43 bool needLog = (event == BluetoothSwitchEvent::BLUETOOTH_ON ||
44 event == BluetoothSwitchEvent::BLUETOOTH_OFF ||
45 event == BluetoothSwitchEvent::BLUETOOTH_HALF) ? isBtSwitchProcessing_.load() : true;
46 if (needLog) {
47 HILOGI("Process Event: %{public}s", ToString(event));
48 }
49 }
50
ProcessBluetoothSwitchEvent(BluetoothSwitchEvent event)51 int BluetoothSwitchModule::ProcessBluetoothSwitchEvent(BluetoothSwitchEvent event)
52 {
53 CHECK_AND_RETURN_LOG_RET(switchAction_, BT_ERR_INTERNAL_ERROR, "switchAction is nullptr");
54
55 std::lock_guard<std::mutex> lock(bluetoothSwitchEventMutex_);
56 LogBluetoothSwitchEvent(event);
57 switch (event) {
58 case BluetoothSwitchEvent::ENABLE_BLUETOOTH:
59 return ProcessEnableBluetoothEvent();
60 case BluetoothSwitchEvent::DISABLE_BLUETOOTH:
61 return ProcessDisableBluetoothEvent();
62 case BluetoothSwitchEvent::ENABLE_BLUETOOTH_TO_RESTRICE_MODE:
63 return ProcessEnableBluetoothToRestrictModeEvent();
64 case BluetoothSwitchEvent::BLUETOOTH_ON:
65 return ProcessBluetoothOnEvent();
66 case BluetoothSwitchEvent::BLUETOOTH_OFF:
67 return ProcessBluetoothOffEvent();
68 case BluetoothSwitchEvent::BLUETOOTH_HALF:
69 return ProcessBluetoothHalfEvent();
70 default: break;
71 }
72 HILOGI("Invalid event: %{public}s", ToString(event));
73 return BT_ERR_INTERNAL_ERROR;
74 }
75
OnTaskTimeout(void)76 void BluetoothSwitchModule::OnTaskTimeout(void)
77 {
78 HILOGW("Bluetooth switch action timeout, clear resources");
79 std::lock_guard<std::mutex> lock(bluetoothSwitchEventMutex_);
80 isBtSwitchProcessing_ = false;
81 cachedEventVec_.clear();
82 }
83
ProcessBluetoothSwitchAction(std::function<int (void)> action,BluetoothSwitchEvent cachedEvent)84 int BluetoothSwitchModule::ProcessBluetoothSwitchAction(
85 std::function<int(void)> action, BluetoothSwitchEvent cachedEvent)
86 {
87 if (isBtSwitchProcessing_.load()) {
88 cachedEventVec_.push_back(cachedEvent);
89 HILOGW("BtSwich action is processing, cache the %{public}s event", ToString(cachedEvent));
90 return BT_NO_ERROR;
91 }
92
93 ffrt::task_attr taskAttr;
94 taskAttr.name("bt_switch").delay(taskTimeout_);
95 taskTimeoutHandle_ = ffrtQueue_.submit_h([switchWptr = weak_from_this()]() {
96 auto switchSptr = switchWptr.lock();
97 if (switchSptr == nullptr) {
98 HILOGE("switchSptr is nullptr");
99 return;
100 }
101 switchSptr->OnTaskTimeout();
102 }, taskAttr);
103
104 isBtSwitchProcessing_ = true;
105 int ret = action();
106 if (ret != BT_NO_ERROR) {
107 isBtSwitchProcessing_ = false;
108 ffrtQueue_.cancel(taskTimeoutHandle_);
109 }
110 // Considering interface compatibility, when a thiry party app invokes the Bluetooth switch interface,
111 // a dialog box is displayed, indicating that the call is success.
112 if (ret == BT_ERR_DIALOG_FOR_USER_CONFIRM) {
113 ret = BT_NO_ERROR;
114 }
115 return ret;
116 }
117
ProcessEnableBluetoothEvent(void)118 int BluetoothSwitchModule::ProcessEnableBluetoothEvent(void)
119 {
120 return ProcessBluetoothSwitchAction(
121 [this]() { return switchAction_->EnableBluetooth(); },
122 BluetoothSwitchEvent::ENABLE_BLUETOOTH);
123 }
124
ProcessDisableBluetoothEvent(void)125 int BluetoothSwitchModule::ProcessDisableBluetoothEvent(void)
126 {
127 return ProcessBluetoothSwitchAction(
128 [this]() { return switchAction_->DisableBluetooth(); },
129 BluetoothSwitchEvent::DISABLE_BLUETOOTH);
130 }
131
ProcessEnableBluetoothToRestrictModeEvent(void)132 int BluetoothSwitchModule::ProcessEnableBluetoothToRestrictModeEvent(void)
133 {
134 return ProcessBluetoothSwitchAction(
135 [this]() { return switchAction_->EnableBluetoothToRestrictMode(); },
136 BluetoothSwitchEvent::ENABLE_BLUETOOTH_TO_RESTRICE_MODE);
137 }
138
ProcessBluetoothOnEvent(void)139 int BluetoothSwitchModule::ProcessBluetoothOnEvent(void)
140 {
141 return ProcessBluetoothSwitchActionEnd(
142 BluetoothSwitchEvent::ENABLE_BLUETOOTH,
143 {BluetoothSwitchEvent::DISABLE_BLUETOOTH});
144 }
145
ProcessBluetoothOffEvent(void)146 int BluetoothSwitchModule::ProcessBluetoothOffEvent(void)
147 {
148 return ProcessBluetoothSwitchActionEnd(
149 BluetoothSwitchEvent::DISABLE_BLUETOOTH,
150 {BluetoothSwitchEvent::ENABLE_BLUETOOTH, BluetoothSwitchEvent::ENABLE_BLUETOOTH_TO_RESTRICE_MODE});
151 }
152
ProcessBluetoothHalfEvent(void)153 int BluetoothSwitchModule::ProcessBluetoothHalfEvent(void)
154 {
155 return ProcessBluetoothSwitchActionEnd(
156 BluetoothSwitchEvent::ENABLE_BLUETOOTH_TO_RESTRICE_MODE,
157 {BluetoothSwitchEvent::ENABLE_BLUETOOTH, BluetoothSwitchEvent::DISABLE_BLUETOOTH});
158 }
159
ProcessBluetoothSwitchActionEnd(BluetoothSwitchEvent curSwitchActionEvent,std::vector<BluetoothSwitchEvent> expectedEventVec)160 int BluetoothSwitchModule::ProcessBluetoothSwitchActionEnd(
161 BluetoothSwitchEvent curSwitchActionEvent, std::vector<BluetoothSwitchEvent> expectedEventVec)
162 {
163 isBtSwitchProcessing_ = false;
164 ffrtQueue_.cancel(taskTimeoutHandle_);
165 DeduplicateCacheEvent(curSwitchActionEvent);
166
167 // Expect process the next event is in 'expectedProcessEventVec'
168 auto it = std::find_if(cachedEventVec_.begin(), cachedEventVec_.end(), [&expectedEventVec](auto event) {
169 return std::find(expectedEventVec.begin(), expectedEventVec.end(), event) != expectedEventVec.end();
170 });
171 if (it != cachedEventVec_.end()) {
172 if (it != cachedEventVec_.begin()) {
173 LogCacheEventIgnored(std::vector<BluetoothSwitchEvent>(cachedEventVec_.begin(), it));
174 }
175 // Ignore the cached event before 'expectedEventVec'
176 BluetoothSwitchEvent event = *it;
177 cachedEventVec_.erase(cachedEventVec_.begin(), it + 1);
178 return ProcessBluetoothSwitchCachedEvent(event);
179 }
180
181 cachedEventVec_.clear();
182 return BT_NO_ERROR;
183 }
184
ProcessBluetoothSwitchCachedEvent(BluetoothSwitchEvent event)185 int BluetoothSwitchModule::ProcessBluetoothSwitchCachedEvent(BluetoothSwitchEvent event)
186 {
187 HILOGI("Auto process cached %{public}s event", ToString(event));
188 ffrtQueue_.submit([switchWptr = weak_from_this(), event]() {
189 auto switchSptr = switchWptr.lock();
190 if (switchSptr == nullptr) {
191 HILOGE("switchSptr is nullptr");
192 return;
193 }
194 switchSptr->ProcessBluetoothSwitchEvent(event);
195 });
196 return BT_NO_ERROR;
197 }
198
DeduplicateCacheEvent(BluetoothSwitchEvent curEvent)199 void BluetoothSwitchModule::DeduplicateCacheEvent(BluetoothSwitchEvent curEvent)
200 {
201 // 从缓存事件列表里,找到最后一个 curEvent,保留该事件之后的缓存事件
202 auto it = std::find(cachedEventVec_.rbegin(), cachedEventVec_.rend(), curEvent);
203 if (it != cachedEventVec_.rend()) {
204 // The it.base() is greater than cachedEventVec_.begin(), so std::distance > 0.
205 size_t pos = static_cast<size_t>(std::distance(cachedEventVec_.begin(), it.base())) - 1;
206
207 LogCacheEventIgnored(
208 std::vector<BluetoothSwitchEvent>(cachedEventVec_.begin(), cachedEventVec_.begin() + pos + 1));
209 cachedEventVec_.erase(cachedEventVec_.begin(), cachedEventVec_.begin() + pos + 1);
210 }
211 }
212
LogCacheEventIgnored(std::vector<BluetoothSwitchEvent> eventVec)213 void BluetoothSwitchModule::LogCacheEventIgnored(std::vector<BluetoothSwitchEvent> eventVec)
214 {
215 std::string log = "";
216 for (size_t i = 0; i < eventVec.size(); i++) {
217 // The last event current process event, not ignored
218 log += ToString(eventVec[i]);
219 log += " ";
220 }
221 if (!log.empty()) {
222 HILOGW("Ignore cache event: %{public}s", log.c_str());
223 }
224 }
225 } // namespace Bluetooth
226 } // namespace OHOS
227