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
16 #include <memory>
17 #include <unordered_map>
18
19 #include "ability_manager_client.h"
20 #include "assert.h"
21 #include "assert_fault_task_thread.h"
22 #include "assert_fault_callback.h"
23 #include "hilog_tag_wrapper.h"
24 #include "main_thread.h"
25 #include "string_wrapper.h"
26
27 namespace OHOS {
28 namespace AbilityRuntime {
29 namespace {
30 std::unordered_map<AAFwk::UserStatus, Assert_Status> assertResultMap = {
31 {AAFwk::UserStatus::ASSERT_TERMINATE, Assert_Status::ASSERT_ABORT},
32 {AAFwk::UserStatus::ASSERT_CONTINUE, Assert_Status::ASSERT_IGNORE},
33 {AAFwk::UserStatus::ASSERT_RETRY, Assert_Status::ASSERT_RETRY},
34 };
35 const AAFwk::UserStatus ASSERT_FAULT_DEFAULT_VALUE = AAFwk::UserStatus::ASSERT_TERMINATE; // default value is abort
36 constexpr char ASSERT_FAULT_THREAD[] = "assertFaultTHR";
37 constexpr char ASSERT_FAULT_DETAIL[] = "assertFaultDialogDetail";
38 constexpr char ASSERT_FAULT_PROMPT[] = "\n\n(Press Retry to debug the application)";
39 }
40
RequestAssertResult(const std::string & exprStr)41 AAFwk::UserStatus AssertFaultTaskThread::RequestAssertResult(const std::string &exprStr)
42 {
43 if (assertHandler_ == nullptr) {
44 TAG_LOGE(AAFwkTag::APPKIT, "Assert handler is nullptr");
45 return ASSERT_FAULT_DEFAULT_VALUE;
46 }
47
48 auto assertResult = ASSERT_FAULT_DEFAULT_VALUE;
49 std::weak_ptr<AssertFaultTaskThread> weak = shared_from_this();
50 assertHandler_->PostSyncTask([weak, exprStr, &assertResult]() {
51 TAG_LOGD(AAFwkTag::APPKIT, "called");
52 auto assertFaultTask = weak.lock();
53 if (assertFaultTask == nullptr) {
54 TAG_LOGE(AAFwkTag::APPKIT, "Assert fault task instance is nullptr");
55 return;
56 }
57 assertResult = assertFaultTask->HandleAssertCallback(exprStr);
58 }, "AssertFaultTaskThread::RequestAssertResult");
59 return assertResult;
60 }
61
ConvertAssertResult(AAFwk::UserStatus status)62 Assert_Status ConvertAssertResult(AAFwk::UserStatus status)
63 {
64 auto result = assertResultMap.find(status);
65 if (result == assertResultMap.end()) {
66 TAG_LOGE(AAFwkTag::APPKIT, "Find %{public}d failed, convert assert reuslt error", status);
67 return Assert_Status::ASSERT_ABORT;
68 }
69 return result->second;
70 }
71
AssertCallback(AssertFailureInfo assertFail)72 static Assert_Status AssertCallback(AssertFailureInfo assertFail)
73 {
74 TAG_LOGD(AAFwkTag::APPKIT, "called");
75 auto instance = DelayedSingleton<AbilityRuntime::AssertFaultTaskThread>::GetInstance();
76 if (instance == nullptr) {
77 TAG_LOGE(AAFwkTag::APPKIT, "Invalid Instance");
78 return Assert_Status::ASSERT_ABORT;
79 }
80
81 std::string textFile = std::string("File:\n") +
82 (assertFail.file == nullptr ? "Unknown" : std::string(assertFail.file));
83 std::string textFunc = std::string("\nFunction: ") +
84 (assertFail.function == nullptr ? "Unknown" : std::string(assertFail.function));
85 std::string textLine = std::string("\nLine: ") + std::to_string(assertFail.line);
86 std::string textExpression = std::string("\n\nExpression:\n") +
87 (assertFail.expression == nullptr ? "Unknown" : std::string(assertFail.expression));
88 std::string textDetail = textFile + textFunc + textLine + textExpression + ASSERT_FAULT_PROMPT;
89
90 auto ret = ConvertAssertResult(instance->RequestAssertResult(textDetail));
91 TAG_LOGD(AAFwkTag::APPKIT, "Return sync task result is %{public}d", static_cast<int32_t>(ret));
92 return ret;
93 }
94
InitAssertFaultTask(const wptr<AppExecFwk::MainThread> & weak,bool isDebugModule)95 void AssertFaultTaskThread::InitAssertFaultTask(const wptr<AppExecFwk::MainThread> &weak, bool isDebugModule)
96 {
97 auto runner = AppExecFwk::EventRunner::Create(ASSERT_FAULT_THREAD);
98 if (runner == nullptr) {
99 TAG_LOGE(AAFwkTag::APPKIT, "Runner is nullptr");
100 return;
101 }
102
103 auto assertHandler = std::make_shared<AppExecFwk::EventHandler>(runner);
104 if (assertHandler == nullptr) {
105 TAG_LOGE(AAFwkTag::APPKIT, "Handler is nullptr");
106 runner->Stop();
107 return;
108 }
109
110 set_assert_callback(AssertCallback);
111 isDebugModule_ = isDebugModule;
112 mainThread_ = weak;
113 assertRunner_ = runner;
114 assertHandler_ = assertHandler;
115 }
116
Stop()117 void AssertFaultTaskThread::Stop()
118 {
119 if (assertRunner_ == nullptr) {
120 TAG_LOGE(AAFwkTag::APPKIT, "Assert runner is nullptr");
121 return;
122 }
123 assertRunner_->Stop();
124 assertRunner_.reset();
125 }
126
HandleAssertCallback(const std::string & exprStr)127 AAFwk::UserStatus AssertFaultTaskThread::HandleAssertCallback(const std::string &exprStr)
128 {
129 auto mainThread = mainThread_.promote();
130 if (mainThread == nullptr) {
131 TAG_LOGE(AAFwkTag::APPKIT, "Invalid thread object");
132 return ASSERT_FAULT_DEFAULT_VALUE;
133 }
134
135 if (!isDebugModule_) {
136 mainThread->AssertFaultPauseMainThreadDetection();
137 }
138 auto assertResult = ASSERT_FAULT_DEFAULT_VALUE;
139 do {
140 sptr<AssertFaultCallback> assertFaultCallback =
141 new (std::nothrow) AssertFaultCallback(shared_from_this());
142 if (assertFaultCallback == nullptr) {
143 TAG_LOGE(AAFwkTag::APPKIT, "Invalid assert fault callback object");
144 break;
145 }
146
147 auto amsClient = AAFwk::AbilityManagerClient::GetInstance();
148 if (amsClient == nullptr) {
149 TAG_LOGE(AAFwkTag::APPKIT, "Invalid client object");
150 break;
151 }
152
153 std::unique_lock<std::mutex> lockAssertResult(assertResultMutex_);
154 AAFwk::WantParams wantParams;
155 wantParams.SetParam(ASSERT_FAULT_DETAIL, AAFwk::String::Box(exprStr));
156 auto err = amsClient->RequestAssertFaultDialog(assertFaultCallback->AsObject(), wantParams);
157 if (err != ERR_OK) {
158 TAG_LOGE(AAFwkTag::APPKIT, "Request assert fault dialog failed");
159 break;
160 }
161
162 assertResultCV_.wait(lockAssertResult);
163 assertResult = assertFaultCallback->GetAssertResult();
164 } while (false);
165
166 if (!isDebugModule_) {
167 mainThread->AssertFaultResumeMainThreadDetection();
168 }
169 return assertResult;
170 }
171
NotifyReleaseLongWaiting()172 void AssertFaultTaskThread::NotifyReleaseLongWaiting()
173 {
174 std::unique_lock<std::mutex> lockAssertResult(assertResultMutex_);
175 assertResultCV_.notify_one();
176 }
177 } // namespace AbilityRuntime
178 } // namespace OHOS