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
16 #include "bluetooth_switch_module.h"
17
18 #include <algorithm>
19 #include "bluetooth_errorcode.h"
20 #include "bluetooth_log.h"
21
22 namespace OHOS {
23 namespace Bluetooth {
ToString(BluetoothSwitchEvent event)24 static const char *ToString(BluetoothSwitchEvent event)
25 {
26 switch (event) {
27 case BluetoothSwitchEvent::ENABLE_BLUETOOTH: return "ENABLE_BLUETOOTH";
28 case BluetoothSwitchEvent::DISABLE_BLUETOOTH: return "DISABLE_BLUETOOTH";
29 case BluetoothSwitchEvent::ENABLE_BLUETOOTH_TO_RESTRICE_MODE: return "ENABLE_BLUETOOTH_TO_RESTRICE_MODE";
30 case BluetoothSwitchEvent::BLUETOOTH_ON: return "BLUETOOTH_ON";
31 case BluetoothSwitchEvent::BLUETOOTH_OFF: return "BLUETOOTH_OFF";
32 case BluetoothSwitchEvent::BLUETOOTH_HALF: return "BLUETOOTH_HALF";
33 default: break;
34 }
35 return "Unknown";
36 }
37
LogBluetoothSwitchEvent(BluetoothSwitchEvent event)38 void BluetoothSwitchModule::LogBluetoothSwitchEvent(BluetoothSwitchEvent event)
39 {
40 bool needLog = (event == BluetoothSwitchEvent::BLUETOOTH_ON ||
41 event == BluetoothSwitchEvent::BLUETOOTH_OFF ||
42 event == BluetoothSwitchEvent::BLUETOOTH_HALF) ? isBtSwitchProcessing_.load() : true;
43 if (needLog) {
44 HILOGI("Process Event: %{public}s", ToString(event));
45 }
46 }
47
ProcessBluetoothSwitchEvent(BluetoothSwitchEvent event)48 int BluetoothSwitchModule::ProcessBluetoothSwitchEvent(BluetoothSwitchEvent event)
49 {
50 CHECK_AND_RETURN_LOG_RET(switchAction_, BT_ERR_INTERNAL_ERROR, "switchAction is nullptr");
51
52 std::lock_guard<std::mutex> lock(bluetoothSwitchEventMutex_);
53 LogBluetoothSwitchEvent(event);
54 switch (event) {
55 case BluetoothSwitchEvent::ENABLE_BLUETOOTH:
56 return ProcessEnableBluetoothEvent();
57 case BluetoothSwitchEvent::DISABLE_BLUETOOTH:
58 return ProcessDisableBluetoothEvent();
59 case BluetoothSwitchEvent::ENABLE_BLUETOOTH_TO_RESTRICE_MODE:
60 return ProcessEnableBluetoothToRestrictModeEvent();
61 case BluetoothSwitchEvent::BLUETOOTH_ON:
62 return ProcessBluetoothOnEvent();
63 case BluetoothSwitchEvent::BLUETOOTH_OFF:
64 return ProcessBluetoothOffEvent();
65 case BluetoothSwitchEvent::BLUETOOTH_HALF:
66 return ProcessBluetoothHalfEvent();
67 default: break;
68 }
69 HILOGI("Invalid event: %{public}s", ToString(event));
70 return BT_ERR_INTERNAL_ERROR;
71 }
72
OnTaskTimeout(void)73 void BluetoothSwitchModule::OnTaskTimeout(void)
74 {
75 HILOGW("Bluetooth switch action timeout, clear resources");
76 std::lock_guard<std::mutex> lock(bluetoothSwitchEventMutex_);
77 isBtSwitchProcessing_ = false;
78 cachedEventVec_.clear();
79 }
80
ProcessBluetoothSwitchAction( std::function<int(void)> action, BluetoothSwitchEvent cachedEvent)81 int BluetoothSwitchModule::ProcessBluetoothSwitchAction(
82 std::function<int(void)> action, BluetoothSwitchEvent cachedEvent)
83 {
84 if (isBtSwitchProcessing_.load()) {
85 cachedEventVec_.push_back(cachedEvent);
86 HILOGW("BtSwich action is processing, cache the %{public}s event", ToString(cachedEvent));
87 return BT_NO_ERROR;
88 }
89
90 ffrt::task_attr taskAttr;
91 taskAttr.name("bt_switch").delay(taskTimeout_);
92 taskTimeoutHandle_ = ffrtQueue_.submit_h([switchWptr = weak_from_this()]() {
93 auto switchSptr = switchWptr.lock();
94 if (switchSptr == nullptr) {
95 HILOGE("switchSptr is nullptr");
96 return;
97 }
98 switchSptr->OnTaskTimeout();
99 }, taskAttr);
100
101 isBtSwitchProcessing_ = true;
102 int ret = action();
103 if (ret != BT_NO_ERROR) {
104 isBtSwitchProcessing_ = false;
105 ffrtQueue_.cancel(taskTimeoutHandle_);
106 }
107 return ret;
108 }
109
ProcessEnableBluetoothEvent(void)110 int BluetoothSwitchModule::ProcessEnableBluetoothEvent(void)
111 {
112 return ProcessBluetoothSwitchAction(
113 [this]() { return switchAction_->EnableBluetooth(); },
114 BluetoothSwitchEvent::ENABLE_BLUETOOTH);
115 }
116
ProcessDisableBluetoothEvent(void)117 int BluetoothSwitchModule::ProcessDisableBluetoothEvent(void)
118 {
119 return ProcessBluetoothSwitchAction(
120 [this]() { return switchAction_->DisableBluetooth(); },
121 BluetoothSwitchEvent::DISABLE_BLUETOOTH);
122 }
123
ProcessEnableBluetoothToRestrictModeEvent(void)124 int BluetoothSwitchModule::ProcessEnableBluetoothToRestrictModeEvent(void)
125 {
126 return ProcessBluetoothSwitchAction(
127 [this]() { return switchAction_->EnableBluetoothToRestrictMode(); },
128 BluetoothSwitchEvent::ENABLE_BLUETOOTH_TO_RESTRICE_MODE);
129 }
130
131 int BluetoothSwitchModule::ProcessBluetoothOnEvent(void)
132 {
133 return ProcessBluetoothSwitchActionEnd(
134 BluetoothSwitchEvent::ENABLE_BLUETOOTH,
135 {BluetoothSwitchEvent::DISABLE_BLUETOOTH});
136 }
137
138 int BluetoothSwitchModule::ProcessBluetoothOffEvent(void)
139 {
140 return ProcessBluetoothSwitchActionEnd(
141 BluetoothSwitchEvent::DISABLE_BLUETOOTH,
142 {BluetoothSwitchEvent::ENABLE_BLUETOOTH, BluetoothSwitchEvent::ENABLE_BLUETOOTH_TO_RESTRICE_MODE});
143 }
144
145 int BluetoothSwitchModule::ProcessBluetoothHalfEvent(void)
146 {
147 return ProcessBluetoothSwitchActionEnd(
148 BluetoothSwitchEvent::ENABLE_BLUETOOTH_TO_RESTRICE_MODE,
149 {BluetoothSwitchEvent::ENABLE_BLUETOOTH, BluetoothSwitchEvent::DISABLE_BLUETOOTH});
150 }
151
152 int BluetoothSwitchModule::ProcessBluetoothSwitchActionEnd(
153 BluetoothSwitchEvent curSwitchActionEvent, std::vector<BluetoothSwitchEvent> expectedEventVec)
154 {
155 isBtSwitchProcessing_ = false;
156 ffrtQueue_.cancel(taskTimeoutHandle_);
157 DeduplicateCacheEvent(curSwitchActionEvent);
158
159 // Expect process the next event is in 'expectedProcessEventVec'
160 auto it = std::find_if(cachedEventVec_.begin(), cachedEventVec_.end(), [&expectedEventVec](auto event) {
161 return std::find(expectedEventVec.begin(), expectedEventVec.end(), event) != expectedEventVec.end();
162 });
163 if (it != cachedEventVec_.end()) {
164 if (it != cachedEventVec_.begin()) {
165 LogCacheEventIgnored(std::vector<BluetoothSwitchEvent>(cachedEventVec_.begin(), it));
166 }
167 // Ignore the cached event before 'expectedEventVec'
168 BluetoothSwitchEvent event = *it;
169 cachedEventVec_.erase(cachedEventVec_.begin(), it + 1);
170 return ProcessBluetoothSwitchCachedEvent(event);
171 }
172
173 cachedEventVec_.clear();
174 return BT_NO_ERROR;
175 }
176
177 int BluetoothSwitchModule::ProcessBluetoothSwitchCachedEvent(BluetoothSwitchEvent event)
178 {
179 HILOGI("Auto process cached %{public}s event", ToString(event));
180 ffrtQueue_.submit([switchWptr = weak_from_this(), event]() {
181 auto switchSptr = switchWptr.lock();
182 if (switchSptr == nullptr) {
183 HILOGE("switchSptr is nullptr");
184 return;
185 }
186 switchSptr->ProcessBluetoothSwitchEvent(event);
187 });
188 return BT_NO_ERROR;
189 }
190
191 void BluetoothSwitchModule::DeduplicateCacheEvent(BluetoothSwitchEvent curEvent)
192 {
193 // 从缓存事件列表里,找到最后一个 curEvent,保留该事件之后的缓存事件
194 auto it = std::find(cachedEventVec_.rbegin(), cachedEventVec_.rend(), curEvent);
195 if (it != cachedEventVec_.rend()) {
196 // The it.base() is greater than cachedEventVec_.begin(), so std::distance > 0.
197 size_t pos = static_cast<size_t>(std::distance(cachedEventVec_.begin(), it.base())) - 1;
198
199 LogCacheEventIgnored(
200 std::vector<BluetoothSwitchEvent>(cachedEventVec_.begin(), cachedEventVec_.begin() + pos + 1));
201 cachedEventVec_.erase(cachedEventVec_.begin(), cachedEventVec_.begin() + pos + 1);
202 }
203 }
204
205 void BluetoothSwitchModule::LogCacheEventIgnored(std::vector<BluetoothSwitchEvent> eventVec)
206 {
207 std::string log = "";
208 for (size_t i = 0; i < eventVec.size(); i++) {
209 // The last event current process event, not ignored
210 log += ToString(eventVec[i]);
211 log += " ";
212 }
213 if (!log.empty()) {
214 HILOGW("Ignore cache event: %{public}s", log.c_str());
215 }
216 }
217 } // namespace Bluetooth
218 } // namespace OHOS
219