1 /*
2  * Copyright (c) 2023-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 "insight_intent_execute_manager.h"
17 
18 #include "ability_manager_errors.h"
19 #include "hilog_tag_wrapper.h"
20 #include "insight_intent_execute_callback_interface.h"
21 #include "insight_intent_utils.h"
22 #include "permission_verification.h"
23 #include "want_params_wrapper.h"
24 
25 namespace OHOS {
26 namespace AAFwk {
27 namespace {
28 constexpr size_t INSIGHT_INTENT_EXECUTE_RECORDS_MAX_SIZE = 256;
29 constexpr char EXECUTE_INSIGHT_INTENT_PERMISSION[] = "ohos.permission.EXECUTE_INSIGHT_INTENT";
30 }
31 using namespace AppExecFwk;
32 
OnRemoteDied(const wptr<OHOS::IRemoteObject> & remote)33 void InsightIntentExecuteRecipient::OnRemoteDied(const wptr<OHOS::IRemoteObject> &remote)
34 {
35     TAG_LOGD(AAFwkTag::INTENT, "InsightIntentExecuteRecipient OnRemoteDied, %{public}" PRIu64, intentId_);
36     auto object = remote.promote();
37     if (object == nullptr) {
38         TAG_LOGE(AAFwkTag::INTENT, "null remote object");
39         return;
40     }
41     DelayedSingleton<InsightIntentExecuteManager>::GetInstance()->RemoteDied(intentId_);
42 }
43 
44 InsightIntentExecuteManager::InsightIntentExecuteManager() = default;
45 
46 InsightIntentExecuteManager::~InsightIntentExecuteManager() = default;
47 
CheckAndUpdateParam(uint64_t key,const sptr<IRemoteObject> & callerToken,const std::shared_ptr<AppExecFwk::InsightIntentExecuteParam> & param)48 int32_t InsightIntentExecuteManager::CheckAndUpdateParam(uint64_t key, const sptr<IRemoteObject> &callerToken,
49     const std::shared_ptr<AppExecFwk::InsightIntentExecuteParam> &param)
50 {
51     int32_t result = CheckCallerPermission();
52     if (result != ERR_OK) {
53         return result;
54     }
55     if (callerToken == nullptr) {
56         TAG_LOGE(AAFwkTag::INTENT, "null callerToken");
57         return ERR_INVALID_VALUE;
58     }
59     if (param == nullptr) {
60         TAG_LOGE(AAFwkTag::INTENT, "null param");
61         return ERR_INVALID_VALUE;
62     }
63     if (param->bundleName_.empty() || param->moduleName_.empty() || param->abilityName_.empty() ||
64         param->insightIntentName_.empty()) {
65         TAG_LOGE(AAFwkTag::INTENT, "invalid param");
66         return ERR_INVALID_VALUE;
67     }
68     uint64_t intentId = 0;
69     result = AddRecord(key, callerToken, param->bundleName_, intentId);
70     if (result != ERR_OK) {
71         return result;
72     }
73 
74     param->insightIntentId_ = intentId;
75     return ERR_OK;
76 }
77 
CheckAndUpdateWant(Want & want,ExecuteMode executeMode)78 int32_t InsightIntentExecuteManager::CheckAndUpdateWant(Want &want, ExecuteMode executeMode)
79 {
80     int32_t result = IsValidCall(want);
81     if (result != ERR_OK) {
82         return result;
83     }
84     uint64_t intentId = 0;
85     ElementName elementName = want.GetElement();
86     result = AddRecord(0, nullptr, want.GetBundle(), intentId);
87     if (result != ERR_OK) {
88         return result;
89     }
90 
91     std::string srcEntry;
92     auto ret = AbilityRuntime::InsightIntentUtils::GetSrcEntry(elementName,
93         want.GetStringParam(INSIGHT_INTENT_EXECUTE_PARAM_NAME), executeMode, srcEntry);
94     if (ret != ERR_OK || srcEntry.empty()) {
95         TAG_LOGE(AAFwkTag::INTENT, "empty srcEntry");
96         return ERR_INVALID_VALUE;
97     }
98     want.SetParam(INSIGHT_INTENT_SRC_ENTRY, srcEntry);
99     want.SetParam(INSIGHT_INTENT_EXECUTE_PARAM_ID, std::to_string(intentId));
100     want.SetParam(INSIGHT_INTENT_EXECUTE_PARAM_MODE, executeMode);
101     TAG_LOGD(AAFwkTag::INTENT, "check done. insightIntentId: %{public}" PRIu64, intentId);
102     return ERR_OK;
103 }
104 
AddRecord(uint64_t key,const sptr<IRemoteObject> & callerToken,const std::string & bundleName,uint64_t & intentId)105 int32_t InsightIntentExecuteManager::AddRecord(uint64_t key, const sptr<IRemoteObject> &callerToken,
106     const std::string &bundleName, uint64_t &intentId)
107 {
108     std::lock_guard<ffrt::mutex> lock(mutex_);
109     intentId = ++intentIdCount_;
110     auto record = std::make_shared<InsightIntentExecuteRecord>();
111     record->key = key;
112     record->state = InsightIntentExecuteState::EXECUTING;
113     record->callerToken = callerToken;
114     record->bundleName = bundleName;
115     if (callerToken != nullptr) {
116         record->deathRecipient = sptr<InsightIntentExecuteRecipient>::MakeSptr(intentId);
117         callerToken->AddDeathRecipient(record->deathRecipient);
118     }
119 
120     // replace
121     records_[intentId] = record;
122     if (intentId > INSIGHT_INTENT_EXECUTE_RECORDS_MAX_SIZE) {
123         // save the latest INSIGHT_INTENT_EXECUTE_RECORDS_MAX_SIZE records
124         records_.erase(intentId - INSIGHT_INTENT_EXECUTE_RECORDS_MAX_SIZE);
125     }
126     TAG_LOGD(AAFwkTag::INTENT, "init done, records_ size: %{public}zu", records_.size());
127     return ERR_OK;
128 }
129 
RemoveExecuteIntent(uint64_t intentId)130 int32_t InsightIntentExecuteManager::RemoveExecuteIntent(uint64_t intentId)
131 {
132     std::lock_guard<ffrt::mutex> lock(mutex_);
133     records_.erase(intentId);
134     return ERR_OK;
135 }
136 
ExecuteIntentDone(uint64_t intentId,int32_t resultCode,const AppExecFwk::InsightIntentExecuteResult & result)137 int32_t InsightIntentExecuteManager::ExecuteIntentDone(uint64_t intentId, int32_t resultCode,
138     const AppExecFwk::InsightIntentExecuteResult &result)
139 {
140     std::lock_guard<ffrt::mutex> lock(mutex_);
141     auto findResult = records_.find(intentId);
142     if (findResult == records_.end()) {
143         TAG_LOGE(AAFwkTag::INTENT, "intent not found, id: %{public}" PRIu64, intentId);
144         return ERR_INVALID_VALUE;
145     }
146 
147     std::shared_ptr<InsightIntentExecuteRecord> record = findResult->second;
148     if (record == nullptr) {
149         TAG_LOGE(AAFwkTag::INTENT, "intent record is null, id: %{public}" PRIu64, intentId);
150         return ERR_INVALID_VALUE;
151     }
152 
153     TAG_LOGD(AAFwkTag::INTENT, "callback start, id:%{public}" PRIu64, intentId);
154     if (record->state != InsightIntentExecuteState::EXECUTING) {
155         TAG_LOGW(AAFwkTag::INTENT, "Insight intent execute state is not EXECUTING, id:%{public}" PRIu64, intentId);
156         return ERR_INVALID_OPERATION;
157     }
158     record->state = InsightIntentExecuteState::EXECUTE_DONE;
159     sptr<IInsightIntentExecuteCallback> remoteCallback = iface_cast<IInsightIntentExecuteCallback>(record->callerToken);
160     if (remoteCallback == nullptr) {
161         TAG_LOGE(AAFwkTag::INTENT, "Failed to get IIntentExecuteCallback");
162         return ERR_INVALID_VALUE;
163     }
164     remoteCallback->OnExecuteDone(record->key, resultCode, result);
165     if (record->callerToken != nullptr) {
166         record->callerToken->RemoveDeathRecipient(record->deathRecipient);
167         record->callerToken = nullptr;
168     }
169     TAG_LOGD(AAFwkTag::INTENT, "execute done, records_ size: %{public}zu", records_.size());
170     return ERR_OK;
171 }
172 
RemoteDied(uint64_t intentId)173 int32_t InsightIntentExecuteManager::RemoteDied(uint64_t intentId)
174 {
175     std::lock_guard<ffrt::mutex> lock(mutex_);
176     auto result = records_.find(intentId);
177     if (result == records_.end()) {
178         TAG_LOGE(AAFwkTag::INTENT, "intent not found, id: %{public}" PRIu64, intentId);
179         return ERR_INVALID_VALUE;
180     }
181     if (result->second == nullptr) {
182         TAG_LOGE(AAFwkTag::INTENT, "intent record is null, id: %{public}" PRIu64, intentId);
183         return ERR_INVALID_VALUE;
184     }
185     result->second->callerToken = nullptr;
186     result->second->state = InsightIntentExecuteState::REMOTE_DIED;
187     return ERR_OK;
188 }
189 
GetBundleName(uint64_t intentId,std::string & bundleName) const190 int32_t InsightIntentExecuteManager::GetBundleName(uint64_t intentId, std::string &bundleName) const
191 {
192     std::lock_guard<ffrt::mutex> lock(mutex_);
193     auto result = records_.find(intentId);
194     if (result == records_.end()) {
195         TAG_LOGE(AAFwkTag::INTENT, "intent not found, id: %{public}" PRIu64, intentId);
196         return ERR_INVALID_VALUE;
197     }
198     if (result->second == nullptr) {
199         TAG_LOGE(AAFwkTag::INTENT, "intent record is null, id: %{public}" PRIu64, intentId);
200         return ERR_INVALID_VALUE;
201     }
202     bundleName = result->second->bundleName;
203     return ERR_OK;
204 }
205 
GenerateWant(const std::shared_ptr<AppExecFwk::InsightIntentExecuteParam> & param,Want & want)206 int32_t InsightIntentExecuteManager::GenerateWant(
207     const std::shared_ptr<AppExecFwk::InsightIntentExecuteParam> &param, Want &want)
208 {
209     if (param == nullptr) {
210         TAG_LOGE(AAFwkTag::INTENT, "null param");
211         return ERR_INVALID_VALUE;
212     }
213     want.SetElementName("", param->bundleName_, param->abilityName_, param->moduleName_);
214 
215     if (param->insightIntentParam_ != nullptr) {
216         sptr<AAFwk::IWantParams> pExecuteParams = WantParamWrapper::Box(*param->insightIntentParam_);
217         if (pExecuteParams != nullptr) {
218             WantParams wantParams;
219             wantParams.SetParam(INSIGHT_INTENT_EXECUTE_PARAM_PARAM, pExecuteParams);
220             want.SetParams(wantParams);
221         }
222     }
223 
224     std::string srcEntry;
225     auto ret = AbilityRuntime::InsightIntentUtils::GetSrcEntry(want.GetElement(), param->insightIntentName_,
226         static_cast<AppExecFwk::ExecuteMode>(param->executeMode_), srcEntry);
227     if (!srcEntry.empty()) {
228         want.SetParam(INSIGHT_INTENT_SRC_ENTRY, srcEntry);
229     } else if (ret == ERR_INSIGHT_INTENT_GET_PROFILE_FAILED &&
230         param->executeMode_ == AppExecFwk::ExecuteMode::UI_ABILITY_FOREGROUND) {
231         TAG_LOGI(AAFwkTag::INTENT, "Insight intent srcEntry invalid, may need free install on demand");
232         std::string startTime = std::to_string(std::chrono::duration_cast<std::chrono::milliseconds>(
233             std::chrono::system_clock::now().time_since_epoch()).count());
234         want.SetParam(Want::PARAM_RESV_START_TIME, startTime);
235         want.AddFlags(Want::FLAG_INSTALL_ON_DEMAND);
236     } else {
237         TAG_LOGE(AAFwkTag::INTENT, "Insight intent srcEntry invalid");
238         return ERR_INVALID_VALUE;
239     }
240 
241     want.SetParam(INSIGHT_INTENT_EXECUTE_PARAM_NAME, param->insightIntentName_);
242     want.SetParam(INSIGHT_INTENT_EXECUTE_PARAM_MODE, param->executeMode_);
243     want.SetParam(INSIGHT_INTENT_EXECUTE_PARAM_ID, std::to_string(param->insightIntentId_));
244     if (param->displayId_ != INVALID_DISPLAY_ID) {
245         want.SetParam(Want::PARAM_RESV_DISPLAY_ID, param->displayId_);
246         TAG_LOGD(AAFwkTag::INTENT, "Generate want with displayId: %{public}d", param->displayId_);
247     }
248     return ERR_OK;
249 }
250 
IsValidCall(const Want & want)251 int32_t InsightIntentExecuteManager::IsValidCall(const Want &want)
252 {
253     std::string insightIntentName = want.GetStringParam(INSIGHT_INTENT_EXECUTE_PARAM_NAME);
254     if (insightIntentName.empty()) {
255         TAG_LOGE(AAFwkTag::INTENT, "empty insightIntentName");
256         return ERR_INVALID_VALUE;
257     }
258     TAG_LOGD(AAFwkTag::INTENT, "insightIntentName: %{public}s", insightIntentName.c_str());
259 
260     int32_t ret = CheckCallerPermission();
261     if (ret != ERR_OK) {
262         return ret;
263     }
264     return ERR_OK;
265 }
266 
CheckCallerPermission()267 int32_t InsightIntentExecuteManager::CheckCallerPermission()
268 {
269     bool isSystemAppCall = PermissionVerification::GetInstance()->JudgeCallerIsAllowedToUseSystemAPI();
270     if (!isSystemAppCall) {
271         TAG_LOGE(AAFwkTag::INTENT, "The caller is not system-app, can not use system-api");
272         return ERR_NOT_SYSTEM_APP;
273     }
274 
275     bool isCallingPerm = PermissionVerification::GetInstance()->VerifyCallingPermission(
276         EXECUTE_INSIGHT_INTENT_PERMISSION);
277     if (!isCallingPerm) {
278         TAG_LOGE(AAFwkTag::INTENT, "Permission %{public}s verification failed", EXECUTE_INSIGHT_INTENT_PERMISSION);
279         return ERR_PERMISSION_DENIED;
280     }
281     return ERR_OK;
282 }
283 } // namespace AAFwk
284 } // namespace OHOS
285