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