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 #include "ability_manager_client.h"
16 #include "assert_fault_proxy.h"
17 #include "hilog_tag_wrapper.h"
18 #include "scene_board_judgement.h"
19 #include "task_handler_wrap.h"
20 
21 namespace OHOS {
22 namespace AbilityRuntime {
23 namespace {
24 constexpr char ASSERT_FAULT_DETAIL[] = "assertFaultDialogDetail";
25 constexpr char UIEXTENSION_TYPE_KEY[] = "ability.want.params.uiExtensionType";
26 constexpr int32_t INVALID_USERID = -1;
27 constexpr int32_t MESSAGE_PARCEL_KEY_SIZE = 3;
28 constexpr uint32_t COMMAND_START_DIALOG = 1;
29 }
AssertFaultProxy(const sptr<IRemoteObject> & impl)30 AssertFaultProxy::AssertFaultProxy(const sptr<IRemoteObject> &impl) : IRemoteProxy<IAssertFaultInterface>(impl)
31 {}
32 
NotifyDebugAssertResult(AAFwk::UserStatus status)33 void AssertFaultProxy::NotifyDebugAssertResult(AAFwk::UserStatus status)
34 {
35     TAG_LOGD(AAFwkTag::ABILITYMGR, "Notify user action result to assert fault application.");
36     MessageParcel data;
37     if (!data.WriteInterfaceToken(AssertFaultProxy::GetDescriptor())) {
38         TAG_LOGE(AAFwkTag::ABILITYMGR, "Write interface token failed.");
39         return;
40     }
41 
42     if (!data.WriteInt32(static_cast<int32_t>(status))) {
43         TAG_LOGE(AAFwkTag::ABILITYMGR, "Write status failed.");
44         return;
45     }
46 
47     auto remote = Remote();
48     if (remote == nullptr) {
49         TAG_LOGE(AAFwkTag::ABILITYMGR, "Get remote failed.");
50         return;
51     }
52 
53     MessageParcel reply;
54     MessageOption option(MessageOption::TF_ASYNC);
55     if (remote->SendRequest(MessageCode::NOTIFY_DEBUG_ASSERT_RESULT, data, reply, option) != NO_ERROR) {
56         TAG_LOGE(AAFwkTag::ABILITYMGR, "Remote send request failed.");
57     }
58 
59     ModalSystemAssertUIExtension::GetInstance().DisconnectSystemUI();
60 }
61 
AssertFaultRemoteDeathRecipient(RemoteDiedHandler handler)62 AssertFaultRemoteDeathRecipient::AssertFaultRemoteDeathRecipient(RemoteDiedHandler handler) : handler_(handler)
63 {}
64 
OnRemoteDied(const wptr<IRemoteObject> & remote)65 void AssertFaultRemoteDeathRecipient::OnRemoteDied(const wptr<IRemoteObject> &remote)
66 {
67     if (handler_ == nullptr) {
68         TAG_LOGE(AAFwkTag::ABILITYMGR, "Callback is nullptr.");
69         return;
70     }
71     handler_(remote);
72 }
73 
GetInstance()74 ModalSystemAssertUIExtension &ModalSystemAssertUIExtension::GetInstance()
75 {
76     static ModalSystemAssertUIExtension instance;
77     return instance;
78 }
79 
~ModalSystemAssertUIExtension()80 ModalSystemAssertUIExtension::~ModalSystemAssertUIExtension()
81 {
82     dialogConnectionCallback_ = nullptr;
83 }
84 
GetConnection()85 sptr<ModalSystemAssertUIExtension::AssertDialogConnection> ModalSystemAssertUIExtension::GetConnection()
86 {
87     if (dialogConnectionCallback_ == nullptr) {
88         std::lock_guard lock(dialogConnectionMutex_);
89         if (dialogConnectionCallback_ == nullptr) {
90             dialogConnectionCallback_ = new (std::nothrow) AssertDialogConnection();
91         }
92     }
93 
94     return dialogConnectionCallback_;
95 }
96 
CreateModalUIExtension(const AAFwk::Want & want)97 bool ModalSystemAssertUIExtension::CreateModalUIExtension(const AAFwk::Want &want)
98 {
99     TAG_LOGD(AAFwkTag::ABILITYMGR, "called");
100     std::unique_lock<std::mutex> lockAssertResult(assertResultMutex_);
101     if (reqeustCount_++ != 0) {
102         TAG_LOGD(AAFwkTag::ABILITYMGR, "Task busy, waiting for processing.");
103         assertResultCV_.wait(lockAssertResult);
104     }
105     auto callback = GetConnection();
106     if (callback == nullptr) {
107         TAG_LOGE(AAFwkTag::ABILITYMGR, "Callback is nullptr.");
108         TryNotifyOneWaitingThread();
109         return false;
110     }
111     callback->SetReqeustAssertDialogWant(want);
112     auto abilityManagerClient = AAFwk::AbilityManagerClient::GetInstance();
113     if (abilityManagerClient == nullptr) {
114         TAG_LOGE(AAFwkTag::ABILITYMGR, "ConnectSystemUi AbilityManagerClient is nullptr");
115         TryNotifyOneWaitingThread();
116         return false;
117     }
118     AAFwk::Want systemUIWant;
119     if (Rosen::SceneBoardJudgement::IsSceneBoardEnabled()) {
120         systemUIWant.SetElementName("com.ohos.sceneboard", "com.ohos.sceneboard.systemdialog");
121     } else {
122         systemUIWant.SetElementName("com.ohos.systemui", "com.ohos.systemui.dialog");
123     }
124     auto result = abilityManagerClient->ConnectAbility(systemUIWant, callback, INVALID_USERID);
125     if (result != ERR_OK) {
126         TAG_LOGE(AAFwkTag::ABILITYMGR, "ConnectSystemUi ConnectAbility dialog failed, result = %{public}d", result);
127         TryNotifyOneWaitingThread();
128         return false;
129     }
130     return true;
131 }
132 
DisconnectSystemUI()133 bool ModalSystemAssertUIExtension::DisconnectSystemUI()
134 {
135     TAG_LOGD(AAFwkTag::ABILITYMGR, "called");
136     bool retVal = true;
137     do {
138         auto abilityManagerClient = AAFwk::AbilityManagerClient::GetInstance();
139         if (abilityManagerClient == nullptr) {
140             TAG_LOGE(AAFwkTag::ABILITYMGR, "AbilityManagerClient is nullptr");
141             retVal = false;
142             break;
143         }
144         auto callback = GetConnection();
145         if (callback == nullptr) {
146             TAG_LOGE(AAFwkTag::ABILITYMGR, "Callback is nullptr.");
147             retVal = false;
148             break;
149         }
150         auto result = abilityManagerClient->DisconnectAbility(callback);
151         if (result != ERR_OK) {
152             TAG_LOGE(AAFwkTag::ABILITYMGR, "DisconnectAbility dialog failed, result = %{public}d", result);
153             retVal = false;
154             break;
155         }
156     } while (false);
157 
158     return retVal;
159 }
160 
TryNotifyOneWaitingThreadInner()161 void ModalSystemAssertUIExtension::TryNotifyOneWaitingThreadInner()
162 {
163     std::unique_lock<std::mutex> lockAssertResult(assertResultMutex_);
164     if (--reqeustCount_ > 0) {
165         TAG_LOGD(AAFwkTag::ABILITYMGR, "Notify waiting Thread count is %{public}d.", reqeustCount_);
166         assertResultCV_.notify_one();
167         return;
168     }
169     reqeustCount_ = 0;
170     TAG_LOGD(AAFwkTag::ABILITYMGR, "Counter reset to 0.");
171 }
172 
TryNotifyOneWaitingThread()173 void ModalSystemAssertUIExtension::TryNotifyOneWaitingThread()
174 {
175     auto handler = AAFwk::TaskHandlerWrap::GetFfrtHandler();
176     if (handler != nullptr) {
177         auto notifyTask = [] () {
178             ModalSystemAssertUIExtension::GetInstance().TryNotifyOneWaitingThreadInner();
179         };
180         handler->SubmitTask(notifyTask, "TryNotifyOneWaitingThread");
181     }
182 }
183 
SetReqeustAssertDialogWant(const AAFwk::Want & want)184 void ModalSystemAssertUIExtension::AssertDialogConnection::SetReqeustAssertDialogWant(const AAFwk::Want &want)
185 {
186     want_ = want;
187 }
188 
OnAbilityConnectDone(const AppExecFwk::ElementName & element,const sptr<IRemoteObject> & remote,int resultCode)189 void ModalSystemAssertUIExtension::AssertDialogConnection::OnAbilityConnectDone(
190     const AppExecFwk::ElementName &element, const sptr<IRemoteObject> &remote, int resultCode)
191 {
192     TAG_LOGD(AAFwkTag::ABILITYMGR, "called");
193     if (remote == nullptr) {
194         TAG_LOGE(AAFwkTag::ABILITYMGR, "Input remote object is nullptr.");
195         return;
196     }
197 
198     MessageParcel data;
199     MessageParcel reply;
200     MessageOption option;
201     data.WriteInt32(MESSAGE_PARCEL_KEY_SIZE);
202     data.WriteString16(u"bundleName");
203     data.WriteString16(Str8ToStr16(want_.GetElement().GetBundleName()));
204     data.WriteString16(u"abilityName");
205     data.WriteString16(Str8ToStr16(want_.GetElement().GetAbilityName()));
206     data.WriteString16(u"parameters");
207     nlohmann::json param;
208     param[UIEXTENSION_TYPE_KEY] = want_.GetStringParam(UIEXTENSION_TYPE_KEY);
209     param[ASSERT_FAULT_DETAIL] = want_.GetStringParam(ASSERT_FAULT_DETAIL);
210     param[AAFwk::Want::PARAM_ASSERT_FAULT_SESSION_ID] =
211         want_.GetStringParam(AAFwk::Want::PARAM_ASSERT_FAULT_SESSION_ID);
212     std::string paramStr = param.dump();
213     data.WriteString16(Str8ToStr16(paramStr));
214     uint32_t code = !Rosen::SceneBoardJudgement::IsSceneBoardEnabled() ? COMMAND_START_DIALOG :
215         AAFwk::IAbilityConnection::ON_ABILITY_CONNECT_DONE;
216     auto ret = remote->SendRequest(code, data, reply, option);
217     if (ret != ERR_OK) {
218         TAG_LOGE(AAFwkTag::ABILITYMGR, "Show dialog is failed");
219         return;
220     }
221 }
222 
OnAbilityDisconnectDone(const AppExecFwk::ElementName & element,int resultCode)223 void ModalSystemAssertUIExtension::AssertDialogConnection::OnAbilityDisconnectDone(
224     const AppExecFwk::ElementName &element, int resultCode)
225 {
226     TAG_LOGD(AAFwkTag::ABILITYMGR, "called");
227     ModalSystemAssertUIExtension::GetInstance().TryNotifyOneWaitingThread();
228 }
229 } // namespace AbilityRuntime
230 } // namespace OHOS