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