1 /*
2 * Copyright (c) 2023 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 "shutdown_dialog.h"
17
18 #include <atomic>
19 #include <fstream>
20 #include <memory>
21 #include <set>
22 #include <string_ex.h>
23 #include <dlfcn.h>
24
25 #ifdef HAS_MULTIMODALINPUT_INPUT_PART
26 #include <input_manager.h>
27 #include <key_event.h>
28 #include <key_option.h>
29 #endif
30 #include <message_parcel.h>
31
32 #include "config_policy_utils.h"
33 #include "json/reader.h"
34 #include "json/value.h"
35 #include "power_log.h"
36 #include "power_mgr_service.h"
37 #include "power_vibrator.h"
38
39 #ifdef POWER_MANAGER_ENABLE_BLOCK_LONG_PRESS
40 #include "setting_helper.h"
41 #endif
42
43 using namespace OHOS::MMI;
44 using namespace OHOS::AAFwk;
45
46 namespace OHOS {
47 namespace PowerMgr {
48 namespace {
49 static constexpr int32_t LONG_PRESS_DELAY_MS = 3000;
50 static constexpr int32_t INVALID_USERID = -1;
51 static constexpr int32_t MESSAGE_PARCEL_KEY_SIZE = 3;
52 static constexpr int32_t INIT_LONG_PRESS_RETRY = 3;
53 static constexpr uint32_t RETRY_TIME = 1000;
54 std::atomic_bool g_isDialogShow = false;
55 std::atomic_bool g_longPressShow = false;
56 int32_t g_retryCount = 1;
57 sptr<IRemoteObject> g_remoteObject = nullptr;
58 const std::string DIALOG_CONFIG_PATH = "etc/systemui/poweroff_config.json";
59 #ifdef POWER_MANAGER_ENABLE_BLOCK_LONG_PRESS
60 const std::string BLOCK_LONG_PRESS = "1";
61 #endif
62 } // namespace
63
64 std::string ShutdownDialog::bundleName_ = "com.ohos.powerdialog";
65 std::string ShutdownDialog::abilityName_ = "PowerUiExtensionAbility";
66 std::string ShutdownDialog::uiExtensionType_ = "sysDialog/power";
67 std::string ShutdownDialog::dialogBundleName_ = "com.ohos.systemui";
68 std::string ShutdownDialog::dialogAbilityName_ = "com.ohos.systemui.dialog";
69
ShutdownDialog()70 ShutdownDialog::ShutdownDialog() : dialogConnectionCallback_(new DialogAbilityConnection()) {}
71
~ShutdownDialog()72 ShutdownDialog::~ShutdownDialog()
73 {
74 dialogConnectionCallback_ = nullptr;
75 }
76
KeyMonitorInit()77 void ShutdownDialog::KeyMonitorInit()
78 {
79 #ifdef HAS_MULTIMODALINPUT_INPUT_PART
80 POWER_HILOGD(FEATURE_SHUTDOWN, "Initialize the long press powerkey");
81 std::shared_ptr<KeyOption> keyOption = std::make_shared<KeyOption>();
82 std::set<int32_t> preKeys;
83
84 keyOption->SetPreKeys(preKeys);
85 keyOption->SetFinalKey(KeyEvent::KEYCODE_POWER);
86 keyOption->SetFinalKeyDown(true);
87 keyOption->SetFinalKeyDownDuration(LONG_PRESS_DELAY_MS);
88 longPressId_ =
89 InputManager::GetInstance()->SubscribeKeyEvent(keyOption, [this](std::shared_ptr<KeyEvent> keyEvent) {
90 POWER_HILOGI(FEATURE_SHUTDOWN, "Receive long press powerkey");
91 #ifdef POWER_MANAGER_ENABLE_BLOCK_LONG_PRESS
92 //If the power button is shielded, the shutdown screen is not displayed.
93 auto longPress = SettingHelper::GetBlockLongPress();
94 if (longPress == BLOCK_LONG_PRESS) {
95 POWER_HILOGI(FEATURE_SHUTDOWN, "need block power.");
96 return;
97 }
98 #endif
99 ConnectSystemUi();
100 StartVibrator();
101 });
102 if (longPressId_ < ERR_OK) {
103 if (g_retryCount <= INIT_LONG_PRESS_RETRY) {
104 POWER_HILOGI(FEATURE_SHUTDOWN, "SubscribeKey long press failed errcode = %{public}d, Try again in 1 second",
105 longPressId_);
106 FFRTTask task = [this] {
107 KeyMonitorInit();
108 };
109 FFRTUtils::SubmitDelayTask(task, RETRY_TIME, queue_);
110 g_retryCount++;
111 }
112 return;
113 }
114 POWER_HILOGI(FEATURE_SHUTDOWN, "SubscribeKey long press success");
115 #endif
116 }
117
KeyMonitorCancel()118 void ShutdownDialog::KeyMonitorCancel()
119 {
120 #ifdef HAS_MULTIMODALINPUT_INPUT_PART
121 InputManager* inputManager = InputManager::GetInstance();
122 if (inputManager == nullptr) {
123 POWER_HILOGW(FEATURE_SHUTDOWN, "InputManager is null");
124 return;
125 }
126 if (longPressId_ >= ERR_OK) {
127 inputManager->UnsubscribeKeyEvent(longPressId_);
128 }
129 longPressId_ = 0;
130 #endif
131 }
132
ConnectSystemUi()133 bool ShutdownDialog::ConnectSystemUi()
134 {
135 if (g_isDialogShow) {
136 AppExecFwk::ElementName element;
137 dialogConnectionCallback_->OnAbilityConnectDone(element, g_remoteObject, INVALID_USERID);
138 POWER_HILOGW(FEATURE_SHUTDOWN, "power dialog has been show");
139 return true;
140 }
141
142 void *handler = dlopen("libpower_ability.z.so", RTLD_LAZY | RTLD_NODELETE);
143 if (handler == nullptr) {
144 POWER_HILOGE(FEATURE_SHUTDOWN, "dlopen libpower_ability.z.so failed, reason : %{public}s", dlerror());
145 return false;
146 }
147
148 Want want;
149 want.SetElementName(dialogBundleName_, dialogAbilityName_);
150 auto powerConnectAbility = reinterpret_cast<void (*)(const Want&, const sptr<IAbilityConnection>&,
151 int32_t)>(dlsym(handler, "PowerConnectAbility"));
152 if (powerConnectAbility == nullptr) {
153 POWER_HILOGE(FEATURE_SHUTDOWN, "find PowerConnectAbility function failed, reason : %{public}s", dlerror());
154 #ifndef FUZZ_TEST
155 dlclose(handler);
156 #endif
157 handler = nullptr;
158 return false;
159 }
160 powerConnectAbility(want, dialogConnectionCallback_, INVALID_USERID);
161 #ifndef FUZZ_TEST
162 dlclose(handler);
163 #endif
164 handler = nullptr;
165 return true;
166 }
167
IsLongPress() const168 bool ShutdownDialog::IsLongPress() const
169 {
170 return g_longPressShow;
171 }
172
ResetLongPressFlag()173 void ShutdownDialog::ResetLongPressFlag()
174 {
175 g_longPressShow = false;
176 }
177
LoadDialogConfig()178 void ShutdownDialog::LoadDialogConfig()
179 {
180 char buf[MAX_PATH_LEN];
181 char* configPath = GetOneCfgFile(DIALOG_CONFIG_PATH.c_str(), buf, MAX_PATH_LEN);
182 if (configPath == nullptr || *configPath == '\0') {
183 POWER_HILOGI(COMP_UTILS, "do not find shutdown off json");
184 return;
185 }
186
187 std::ifstream inputStream(configPath, std::ios::in | std::ios::binary);
188 std::string contentStr(std::istreambuf_iterator<char> {inputStream}, std::istreambuf_iterator<char> {});
189 Json::Reader reader;
190 Json::Value root;
191 if (!reader.parse(contentStr.data(), contentStr.data() + contentStr.size(), root)) {
192 POWER_HILOGE(COMP_UTILS, "json parse error");
193 return;
194 }
195
196 if (root.isNull() || !root.isObject()) {
197 POWER_HILOGE(COMP_UTILS, "json root invalid[%{public}s]", contentStr.c_str());
198 return;
199 }
200
201 if (!root["bundleName"].isString() ||
202 !root["abilityName"].isString() || !root["uiExtensionType"].isString()) {
203 POWER_HILOGE(COMP_UTILS, "json varibale not support");
204 return;
205 }
206
207 bundleName_ = root["bundleName"].asString();
208 abilityName_ = root["abilityName"].asString();
209 uiExtensionType_ = root["uiExtensionType"].asString();
210 dialogBundleName_ = root["bundleName"].asString();
211 dialogAbilityName_ = "com.ohos.sceneboard.systemdialog";
212 POWER_HILOGI(COMP_UTILS, "PowerOff variables have changed");
213 }
214
OnAbilityConnectDone(const AppExecFwk::ElementName & element,const sptr<IRemoteObject> & remoteObject,int resultCode)215 void ShutdownDialog::DialogAbilityConnection::OnAbilityConnectDone(
216 const AppExecFwk::ElementName& element, const sptr<IRemoteObject>& remoteObject, int resultCode)
217 {
218 POWER_HILOGI(FEATURE_SHUTDOWN, "OnAbilityConnectDone");
219 std::lock_guard lock(mutex_);
220 if (remoteObject == nullptr) {
221 POWER_HILOGW(FEATURE_SHUTDOWN, "remoteObject is nullptr");
222 return;
223 }
224 if (g_remoteObject == nullptr) {
225 g_remoteObject = remoteObject;
226 }
227 FFRTUtils::SubmitTask([remoteObject] {
228 MessageParcel data;
229 MessageParcel reply;
230 MessageOption option;
231 data.WriteInt32(MESSAGE_PARCEL_KEY_SIZE);
232 data.WriteString16(u"bundleName");
233 data.WriteString16(Str8ToStr16(ShutdownDialog::GetBundleName()));
234 data.WriteString16(u"abilityName");
235 data.WriteString16(Str8ToStr16(ShutdownDialog::GetAbilityName()));
236 data.WriteString16(u"parameters");
237 std::string midStr = "\"";
238 // sysDialogZOrder = 2 displayed on the lock screen
239 std::string paramStr = "{\"ability.want.params.uiExtensionType\":" + midStr +
240 ShutdownDialog::GetUiExtensionType() + midStr + ",\"sysDialogZOrder\":2}";
241 data.WriteString16(Str8ToStr16(paramStr));
242 POWER_HILOGI(FEATURE_SHUTDOWN, "show power dialog is begin");
243 const uint32_t cmdCode = 1;
244 int32_t ret = remoteObject->SendRequest(cmdCode, data, reply, option);
245 if (ret != ERR_OK) {
246 POWER_HILOGW(FEATURE_SHUTDOWN, "show power dialog is failed: %{public}d", ret);
247 return;
248 }
249 g_isDialogShow = true;
250 g_longPressShow = true;
251 POWER_HILOGI(FEATURE_SHUTDOWN, "show power dialog is success");
252 auto pms = DelayedSpSingleton<PowerMgrService>::GetInstance();
253 if (pms == nullptr) {
254 return;
255 }
256 pms->RefreshActivityInner(
257 static_cast<int64_t>(time(nullptr)), UserActivityType::USER_ACTIVITY_TYPE_ATTENTION, false);
258 });
259 }
260
StartVibrator()261 void ShutdownDialog::StartVibrator()
262 {
263 std::shared_ptr<PowerVibrator> vibrator = PowerVibrator::GetInstance();
264 std::string scene = "shutdown_diag";
265 vibrator->StartVibrator(scene);
266 }
OnAbilityDisconnectDone(const AppExecFwk::ElementName & element,int resultCode)267 void ShutdownDialog::DialogAbilityConnection::OnAbilityDisconnectDone(
268 const AppExecFwk::ElementName& element, int resultCode)
269 {
270 POWER_HILOGD(FEATURE_SHUTDOWN, "OnAbilityDisconnectDone");
271 std::lock_guard lock(mutex_);
272 g_isDialogShow = false;
273 g_longPressShow = false;
274 g_remoteObject = nullptr;
275 }
276 } // namespace PowerMgr
277 } // namespace OHOS
278