• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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,bool isAsync)51 int BluetoothSwitchModule::ProcessBluetoothSwitchEvent(BluetoothSwitchEvent event, bool isAsync)
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(isAsync);
60         case BluetoothSwitchEvent::DISABLE_BLUETOOTH:
61             return ProcessDisableBluetoothEvent(isAsync);
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(bool isAsync)118 int BluetoothSwitchModule::ProcessEnableBluetoothEvent(bool isAsync)
119 {
120     return ProcessBluetoothSwitchAction(
121         [this, isAsync]() {
122             bool noAutoConnect = noAutoConnect_.load();
123             if (noAutoConnect) {
124                 SetNoAutoConnect(false);
125             }
126             return switchAction_->EnableBluetooth(noAutoConnect, isAsync);
127         },
128         BluetoothSwitchEvent::ENABLE_BLUETOOTH);
129 }
130 
ProcessDisableBluetoothEvent(bool isAsync)131 int BluetoothSwitchModule::ProcessDisableBluetoothEvent(bool isAsync)
132 {
133     return ProcessBluetoothSwitchAction(
134         [this, isAsync]() { return switchAction_->DisableBluetooth(isAsync); },
135         BluetoothSwitchEvent::DISABLE_BLUETOOTH);
136 }
137 
ProcessEnableBluetoothToRestrictModeEvent(void)138 int BluetoothSwitchModule::ProcessEnableBluetoothToRestrictModeEvent(void)
139 {
140     return ProcessBluetoothSwitchAction(
141         [this]() { return switchAction_->EnableBluetoothToRestrictMode(); },
142         BluetoothSwitchEvent::ENABLE_BLUETOOTH_TO_RESTRICE_MODE);
143 }
144 
ProcessBluetoothOnEvent(void)145 int BluetoothSwitchModule::ProcessBluetoothOnEvent(void)
146 {
147     return ProcessBluetoothSwitchActionEnd(
148         BluetoothSwitchEvent::ENABLE_BLUETOOTH,
149         {BluetoothSwitchEvent::DISABLE_BLUETOOTH});
150 }
151 
ProcessBluetoothOffEvent(void)152 int BluetoothSwitchModule::ProcessBluetoothOffEvent(void)
153 {
154     return ProcessBluetoothSwitchActionEnd(
155         BluetoothSwitchEvent::DISABLE_BLUETOOTH,
156         {BluetoothSwitchEvent::ENABLE_BLUETOOTH, BluetoothSwitchEvent::ENABLE_BLUETOOTH_TO_RESTRICE_MODE});
157 }
158 
ProcessBluetoothHalfEvent(void)159 int BluetoothSwitchModule::ProcessBluetoothHalfEvent(void)
160 {
161     return ProcessBluetoothSwitchActionEnd(
162         BluetoothSwitchEvent::ENABLE_BLUETOOTH_TO_RESTRICE_MODE,
163         {BluetoothSwitchEvent::ENABLE_BLUETOOTH, BluetoothSwitchEvent::DISABLE_BLUETOOTH});
164 }
165 
ProcessBluetoothSwitchActionEnd(BluetoothSwitchEvent curSwitchActionEvent,std::vector<BluetoothSwitchEvent> expectedEventVec)166 int BluetoothSwitchModule::ProcessBluetoothSwitchActionEnd(
167     BluetoothSwitchEvent curSwitchActionEvent, std::vector<BluetoothSwitchEvent> expectedEventVec)
168 {
169     isBtSwitchProcessing_ = false;
170     ffrtQueue_.cancel(taskTimeoutHandle_);
171     DeduplicateCacheEvent(curSwitchActionEvent);
172 
173     // Expect process the next event is in 'expectedProcessEventVec'
174     auto it = std::find_if(cachedEventVec_.begin(), cachedEventVec_.end(), [&expectedEventVec](auto event) {
175         return std::find(expectedEventVec.begin(), expectedEventVec.end(), event) != expectedEventVec.end();
176     });
177     if (it != cachedEventVec_.end()) {
178         if (it != cachedEventVec_.begin()) {
179             LogCacheEventIgnored(std::vector<BluetoothSwitchEvent>(cachedEventVec_.begin(), it));
180         }
181         // Ignore the cached event before 'expectedEventVec'
182         BluetoothSwitchEvent event = *it;
183         cachedEventVec_.erase(cachedEventVec_.begin(), it + 1);
184         return ProcessBluetoothSwitchCachedEvent(event);
185     }
186 
187     cachedEventVec_.clear();
188     return BT_NO_ERROR;
189 }
190 
ProcessBluetoothSwitchCachedEvent(BluetoothSwitchEvent event)191 int BluetoothSwitchModule::ProcessBluetoothSwitchCachedEvent(BluetoothSwitchEvent event)
192 {
193     HILOGI("Auto process cached %{public}s event", ToString(event));
194     ffrtQueue_.submit([switchWptr = weak_from_this(), event]() {
195         auto switchSptr = switchWptr.lock();
196         if (switchSptr == nullptr) {
197             HILOGE("switchSptr is nullptr");
198             return;
199         }
200         switchSptr->ProcessBluetoothSwitchEvent(event);
201     });
202     return BT_NO_ERROR;
203 }
204 
DeduplicateCacheEvent(BluetoothSwitchEvent curEvent)205 void BluetoothSwitchModule::DeduplicateCacheEvent(BluetoothSwitchEvent curEvent)
206 {
207     // 从缓存事件列表里,找到最后一个 curEvent,保留该事件之后的缓存事件
208     auto it = std::find(cachedEventVec_.rbegin(), cachedEventVec_.rend(), curEvent);
209     if (it != cachedEventVec_.rend()) {
210         // The it.base() is greater than cachedEventVec_.begin(), so std::distance > 0.
211         size_t pos = static_cast<size_t>(std::distance(cachedEventVec_.begin(), it.base())) - 1;
212 
213         LogCacheEventIgnored(
214             std::vector<BluetoothSwitchEvent>(cachedEventVec_.begin(), cachedEventVec_.begin() + pos + 1));
215         cachedEventVec_.erase(cachedEventVec_.begin(), cachedEventVec_.begin() + pos + 1);
216     }
217 }
218 
LogCacheEventIgnored(std::vector<BluetoothSwitchEvent> eventVec)219 void BluetoothSwitchModule::LogCacheEventIgnored(std::vector<BluetoothSwitchEvent> eventVec)
220 {
221     std::string log = "";
222     for (size_t i = 0; i < eventVec.size(); i++) {
223         // The last event current process event, not ignored
224         log += ToString(eventVec[i]);
225         log += " ";
226     }
227     if (!log.empty()) {
228         HILOGW("Ignore cache event: %{public}s", log.c_str());
229     }
230 }
231 
SetNoAutoConnect(bool noAutoConnect)232 void BluetoothSwitchModule::SetNoAutoConnect(bool noAutoConnect)
233 {
234     noAutoConnect_ = noAutoConnect;
235 }
236 }  // namespace Bluetooth
237 }  // namespace OHOS
238