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