• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <cJSON.h>
31 #include <message_parcel.h>
32 
33 #include "config_policy_utils.h"
34 #include "power_cjson_utils.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     auto inputManager = InputManager::GetInstance();
89     if (!inputManager) {
90         POWER_HILOGE(FEATURE_SHUTDOWN, "KeyMonitorInit inputManager is null");
91         return;
92     }
93     longPressId_ =
94         inputManager->SubscribeKeyEvent(keyOption, [this](std::shared_ptr<KeyEvent> keyEvent) {
95             POWER_KHILOGI(FEATURE_SHUTDOWN, "Receive long press powerkey");
96 #ifdef POWER_MANAGER_ENABLE_BLOCK_LONG_PRESS
97             //If the power button is shielded, the shutdown screen is not displayed.
98             auto longPress = SettingHelper::GetBlockLongPress();
99             if (longPress == BLOCK_LONG_PRESS) {
100                 POWER_HILOGI(FEATURE_SHUTDOWN, "need block power.");
101                 return;
102             }
103 #endif
104             ConnectSystemUi();
105             StartVibrator();
106         });
107     if (longPressId_ < ERR_OK) {
108         if (g_retryCount <= INIT_LONG_PRESS_RETRY) {
109             POWER_HILOGI(FEATURE_SHUTDOWN, "SubscribeKey long press failed errcode = %{public}d, Try again in 1 second",
110                 longPressId_);
111             FFRTTask task = [this] {
112                 KeyMonitorInit();
113             };
114             FFRTUtils::SubmitDelayTask(task, RETRY_TIME, queue_);
115             g_retryCount++;
116         }
117         return;
118     }
119     POWER_HILOGI(FEATURE_SHUTDOWN, "SubscribeKey long press success");
120 #endif
121 }
122 
KeyMonitorCancel()123 void ShutdownDialog::KeyMonitorCancel()
124 {
125 #ifdef HAS_MULTIMODALINPUT_INPUT_PART
126     InputManager* inputManager = InputManager::GetInstance();
127     if (inputManager == nullptr) {
128         POWER_HILOGW(FEATURE_SHUTDOWN, "InputManager is null");
129         return;
130     }
131     if (longPressId_ >= ERR_OK) {
132         inputManager->UnsubscribeKeyEvent(longPressId_);
133     }
134     longPressId_ = 0;
135 #endif
136 }
137 
ConnectSystemUi()138 bool ShutdownDialog::ConnectSystemUi()
139 {
140     if (g_isDialogShow) {
141         AppExecFwk::ElementName element;
142         dialogConnectionCallback_->OnAbilityConnectDone(element, g_remoteObject, INVALID_USERID);
143         POWER_HILOGW(FEATURE_SHUTDOWN, "power dialog has been show");
144         return true;
145     }
146 
147     Want want;
148     want.SetElementName(dialogBundleName_, dialogAbilityName_);
149 
150     void *handler = dlopen("libpower_ability.z.so", RTLD_NOW | RTLD_NODELETE);
151     if (handler == nullptr) {
152         POWER_HILOGE(FEATURE_SHUTDOWN, "dlopen libpower_ability.z.so failed, reason : %{public}s", dlerror());
153         return false;
154     }
155 
156     auto powerConnectAbility = reinterpret_cast<void (*)(const Want&, const sptr<IAbilityConnection>&,
157         int32_t)>(dlsym(handler, "PowerConnectAbility"));
158     if (powerConnectAbility == nullptr) {
159         POWER_HILOGE(FEATURE_SHUTDOWN, "find PowerConnectAbility function failed, reason : %{public}s", dlerror());
160 #ifndef FUZZ_TEST
161         dlclose(handler);
162 #endif
163         handler = nullptr;
164         return false;
165     }
166     powerConnectAbility(want, dialogConnectionCallback_, INVALID_USERID);
167 #ifndef FUZZ_TEST
168     dlclose(handler);
169 #endif
170     handler = nullptr;
171     return true;
172 }
173 
IsLongPress() const174 bool ShutdownDialog::IsLongPress() const
175 {
176     return g_longPressShow;
177 }
178 
ResetLongPressFlag()179 void ShutdownDialog::ResetLongPressFlag()
180 {
181     g_longPressShow = false;
182 }
183 
LoadDialogConfig()184 void ShutdownDialog::LoadDialogConfig()
185 {
186     char buf[MAX_PATH_LEN];
187     char* configPath = GetOneCfgFile(DIALOG_CONFIG_PATH.c_str(), buf, MAX_PATH_LEN);
188     if (configPath == nullptr || *configPath == '\0') {
189         POWER_HILOGI(COMP_UTILS, "do not find shutdown off json");
190         return;
191     }
192 
193     std::ifstream inputStream(configPath, std::ios::in | std::ios::binary);
194     std::string contentStr(std::istreambuf_iterator<char> {inputStream}, std::istreambuf_iterator<char> {});
195     if (contentStr.empty()) {
196         POWER_HILOGE(COMP_UTILS, "json file is empty");
197         return;
198     }
199     ParseJsonConfig(contentStr);
200 }
201 
ParseJsonConfig(std::string & contentStr)202 void ShutdownDialog::ParseJsonConfig(std::string& contentStr)
203 {
204     cJSON* root = cJSON_Parse(contentStr.c_str());
205     if (!root) {
206         POWER_HILOGE(COMP_UTILS, "json parse error[%{public}s]", contentStr.c_str());
207         return;
208     }
209 
210     if (!cJSON_IsObject(root)) {
211         POWER_HILOGE(COMP_UTILS, "json root invalid");
212         cJSON_Delete(root);
213         return;
214     }
215 
216     cJSON* bundleNameItem = cJSON_GetObjectItemCaseSensitive(root, "bundleName");
217     cJSON* abilityNameItem = cJSON_GetObjectItemCaseSensitive(root, "abilityName");
218     cJSON* uiExtensionTypeItem = cJSON_GetObjectItemCaseSensitive(root, "uiExtensionType");
219     if (!PowerMgrJsonUtils::IsValidJsonString(bundleNameItem) ||
220         !PowerMgrJsonUtils::IsValidJsonString(abilityNameItem) ||
221         !PowerMgrJsonUtils::IsValidJsonString(uiExtensionTypeItem)) {
222         POWER_HILOGE(COMP_UTILS, "json variable not supported");
223         cJSON_Delete(root);
224         return;
225     }
226 
227     bundleName_ = bundleNameItem->valuestring;
228     abilityName_ = abilityNameItem->valuestring;
229     uiExtensionType_ = uiExtensionTypeItem->valuestring;
230     dialogBundleName_ = bundleNameItem->valuestring;
231     dialogAbilityName_ = "com.ohos.sceneboard.systemdialog";
232     POWER_HILOGI(COMP_UTILS, "PowerOff variables have changed");
233     cJSON_Delete(root);
234 }
235 
OnAbilityConnectDone(const AppExecFwk::ElementName & element,const sptr<IRemoteObject> & remoteObject,int resultCode)236 void ShutdownDialog::DialogAbilityConnection::OnAbilityConnectDone(
237     const AppExecFwk::ElementName& element, const sptr<IRemoteObject>& remoteObject, int resultCode)
238 {
239     POWER_HILOGI(FEATURE_SHUTDOWN, "OnAbilityConnectDone");
240     std::lock_guard lock(mutex_);
241     if (remoteObject == nullptr) {
242         POWER_HILOGW(FEATURE_SHUTDOWN, "remoteObject is nullptr");
243         return;
244     }
245     if (g_remoteObject == nullptr) {
246         g_remoteObject = remoteObject;
247     }
248     FFRTUtils::SubmitTask([remoteObject] {
249         MessageParcel data;
250         MessageParcel reply;
251         MessageOption option;
252         data.WriteInt32(MESSAGE_PARCEL_KEY_SIZE);
253         data.WriteString16(u"bundleName");
254         data.WriteString16(Str8ToStr16(ShutdownDialog::GetBundleName()));
255         data.WriteString16(u"abilityName");
256         data.WriteString16(Str8ToStr16(ShutdownDialog::GetAbilityName()));
257         data.WriteString16(u"parameters");
258         std::string midStr = "\"";
259         // sysDialogZOrder = 2 displayed on the lock screen
260         std::string paramStr = "{\"ability.want.params.uiExtensionType\":" + midStr +
261             ShutdownDialog::GetUiExtensionType() + midStr + ",\"sysDialogZOrder\":2}";
262         data.WriteString16(Str8ToStr16(paramStr));
263         POWER_HILOGI(FEATURE_SHUTDOWN, "show power dialog is begin");
264         const uint32_t cmdCode = 1;
265         int32_t ret = remoteObject->SendRequest(cmdCode, data, reply, option);
266         if (ret != ERR_OK) {
267             POWER_HILOGW(FEATURE_SHUTDOWN, "show power dialog is failed: %{public}d", ret);
268             return;
269         }
270         g_isDialogShow = true;
271         g_longPressShow = true;
272         POWER_HILOGI(FEATURE_SHUTDOWN, "show power dialog is success");
273         auto pms = DelayedSpSingleton<PowerMgrService>::GetInstance();
274         if (pms == nullptr) {
275             return;
276         }
277         pms->RefreshActivityInner(
278             static_cast<int64_t>(time(nullptr)), UserActivityType::USER_ACTIVITY_TYPE_ATTENTION, false);
279     });
280 }
281 
StartVibrator()282 void ShutdownDialog::StartVibrator()
283 {
284     std::shared_ptr<PowerVibrator> vibrator = PowerVibrator::GetInstance();
285     std::string scene = "shutdown_diag";
286     vibrator->StartVibrator(scene);
287 }
OnAbilityDisconnectDone(const AppExecFwk::ElementName & element,int resultCode)288 void ShutdownDialog::DialogAbilityConnection::OnAbilityDisconnectDone(
289     const AppExecFwk::ElementName& element, int resultCode)
290 {
291     POWER_HILOGD(FEATURE_SHUTDOWN, "OnAbilityDisconnectDone");
292     std::lock_guard lock(mutex_);
293     g_isDialogShow = false;
294     g_longPressShow = false;
295     g_remoteObject = nullptr;
296 }
297 } // namespace PowerMgr
298 } // namespace OHOS
299