1 /*
2 * Copyright (c) 2025 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 <string>
16 #include <ani.h>
17 #include "ani_plugin_callback.h"
18 #include "ani_plugin_component_util.h"
19 #include "ani_common_want.h"
20 #include "ani_plugin_callback_mgr.h"
21 #include "base/log/log_wrapper.h"
22 #include "core/components/plugin/plugin_component_manager.h"
23 #include "ipc_skeleton.h"
24 #include "tokenid_kit.h"
25
26 namespace {
27 const char ANI_PLUGINCOMPONENT_NS[] = "L@ohos/pluginComponent/pluginComponentManager;";
28 } // namespace
29
30 namespace OHOS::Ace::Ani {
31 using namespace OHOS::Ace;
32
GetAniWantPropertyByName(ani_env * env,ani_object parameters,std::string propertyName,OHOS::AAFwk::Want & want)33 static bool GetAniWantPropertyByName(ani_env* env, ani_object parameters, std::string propertyName,
34 OHOS::AAFwk::Want &want)
35 {
36 ani_ref wantAni;
37 env->Object_GetPropertyByName_Ref(parameters, propertyName.c_str(), &wantAni);
38 ani_boolean isUndefined = true;
39 if (ANI_OK != env->Reference_IsUndefined(wantAni, &isUndefined) || isUndefined) {
40 LOGE("plugin-ani GetAniWantPropertyByName %{public}s is null", propertyName.c_str());
41 return false;
42 }
43 auto ownerWant = reinterpret_cast<ani_object>(wantAni);
44 bool ret = OHOS::AppExecFwk::UnwrapWant(env, ownerWant, want);
45 if (!ret) {
46 LOGE("plugin-ani GetAniWantPropertyByName %{public}s error", propertyName.c_str());
47 }
48 return ret;
49 }
50
ParsePushAndRequestParameters(ani_env * env,ACEAsyncJSCallbackInfo * asyncCallbackInfo,ani_object parameters)51 static bool ParsePushAndRequestParameters(ani_env* env, ACEAsyncJSCallbackInfo* asyncCallbackInfo,
52 ani_object parameters)
53 {
54 // name(string) of PushParameterForStage
55 std::string name;
56 if (ANI_OK != GetAniStringPropertyByName(env, parameters, "name", name)) {
57 return false;
58 }
59 asyncCallbackInfo->jsParamList.paramList.PutStringValue("name", name);
60
61 // owner(want) of PushParameterForStage
62 auto ret = GetAniWantPropertyByName(env, parameters, "owner", asyncCallbackInfo->wantStage);
63 if (!ret) {
64 return false;
65 }
66
67 auto selfToken = IPCSkeleton::GetSelfTokenID();
68 if (!Security::AccessToken::TokenIdKit::IsSystemAppByFullTokenID(selfToken)) {
69 LOGE("plugin-ani This application is not system-app, can not use system-api");
70 return false;
71 }
72
73 // target(want) of PushParameterForStage
74 ret = GetAniWantPropertyByName(env, parameters, "target", asyncCallbackInfo->jsParamList.want);
75 if (!ret) {
76 return false;
77 }
78
79 // jsonPath?(string) of PushParameterForStage
80 std::string jsonPath;
81 if (ANI_OK == GetAniStringPropertyByName(env, parameters, "jsonPath", jsonPath)) {
82 asyncCallbackInfo->jsParamList.paramList.PutStringValue("jsonPath", jsonPath);
83 }
84
85 // data(KVObject) of PushParameterForStage
86 std::string data;
87 if (ANI_OK != GetAniKVObjectPropertyByName(env, parameters, "data", data)) {
88 return false;
89 }
90 asyncCallbackInfo->jsParamList.paramList.PutStringValue("data", data);
91 return true;
92 }
93
ParsePushParameters(ani_env * env,ACEAsyncJSCallbackInfo * asyncCallbackInfo,ani_object pushParameters,ani_fn_object fnObj)94 static void ParsePushParameters(ani_env* env, ACEAsyncJSCallbackInfo* asyncCallbackInfo,
95 ani_object pushParameters, ani_fn_object fnObj)
96 {
97 if (!ParsePushAndRequestParameters(env, asyncCallbackInfo, pushParameters)) {
98 return;
99 }
100
101 // extraData(KVObject) of PushParameterForStage
102 std::string extraData;
103 if (ANI_OK != GetAniKVObjectPropertyByName(env, pushParameters, "extraData", extraData)) {
104 return;
105 }
106 asyncCallbackInfo->jsParamList.paramList.PutStringValue("extraData", extraData);
107
108 PluginComponentManager::GetInstance()->Push(asyncCallbackInfo->jsParamList.want,
109 asyncCallbackInfo->jsParamList.paramList.GetStringValue("name"),
110 asyncCallbackInfo->jsParamList.paramList.GetStringValue("jsonPath"),
111 asyncCallbackInfo->jsParamList.paramList.GetStringValue("data"),
112 asyncCallbackInfo->jsParamList.paramList.GetStringValue("extraData"));
113
114 std::vector<ani_ref> vec;
115 ani_ref fnReturnVal;
116 auto param = CreateInt(env, ani_int(0));
117 vec.push_back(param);
118 auto status = env->FunctionalObject_Call(fnObj, vec.size(), vec.data(), &fnReturnVal);
119 if (status != ANI_OK) {
120 LOGE("plugin-ani ParsePushParameters failed %{public}d", status);
121 }
122 }
123
Push(ani_env * env,ani_object pushParameters,ani_fn_object fnObj)124 static void Push([[maybe_unused]] ani_env* env, [[maybe_unused]] ani_object pushParameters, ani_fn_object fnObj)
125 {
126 ACEAsyncJSCallbackInfo* asyncCallbackInfo = AceCreateAsyncJSCallbackInfo(env);
127 ParsePushParameters(env, asyncCallbackInfo, pushParameters, fnObj);
128 AceFreeAsyncJSCallbackInfo(&asyncCallbackInfo);
129 }
130
AceRequestCompleteAsyncCallbackWork(ani_env * env,ACEAsyncJSCallbackInfo * asyncCallbackInfo)131 void AceRequestCompleteAsyncCallbackWork(ani_env* env, ACEAsyncJSCallbackInfo* asyncCallbackInfo)
132 {
133 int32_t pid = IPCSkeleton::GetCallingPid();
134 asyncCallbackInfo->wantStage.SetBundle("plugin" + std::to_string(pid));
135 std::shared_ptr<AceJSPluginRequestParam> param = std::make_shared<AceJSPluginRequestParam>(
136 asyncCallbackInfo->jsParamList.want, asyncCallbackInfo->jsParamList.paramList.GetStringValue("name"),
137 asyncCallbackInfo->jsParamList.paramList.GetStringValue("data"),
138 asyncCallbackInfo->jsParamList.paramList.GetStringValue("jsonPath")
139 );
140 bool ret = ANIPluginCallbackMgr::Instance().RegisterRequestEvent(env, asyncCallbackInfo->wantStage,
141 asyncCallbackInfo->cbInfo, param);
142 LOGI("plugin-ani RegisterRequestEvent result is %{public}d", ret);
143 PluginComponentManager::GetInstance()->Request(asyncCallbackInfo->jsParamList.want,
144 asyncCallbackInfo->jsParamList.paramList.GetStringValue("name"),
145 asyncCallbackInfo->jsParamList.paramList.GetStringValue("jsonPath"),
146 asyncCallbackInfo->jsParamList.paramList.GetStringValue("data"));
147 }
148
Request(ani_env * env,ani_object requestParameters,ani_fn_object fnObj)149 static void Request([[maybe_unused]] ani_env* env, [[maybe_unused]] ani_object requestParameters, ani_fn_object fnObj)
150 {
151 ACEAsyncJSCallbackInfo* asyncCallbackInfo = AceCreateAsyncJSCallbackInfo(env);
152 bool ret = ParsePushAndRequestParameters(env, asyncCallbackInfo, requestParameters);
153 if (!ret) {
154 LOGE("plugin-ani parse request params fail");
155 AceFreeAsyncJSCallbackInfo(&asyncCallbackInfo);
156 return;
157 }
158 ani_ref fnObjGlobalRef = nullptr;
159 if (ANI_OK != env->GlobalReference_Create(reinterpret_cast<ani_ref>(fnObj), &fnObjGlobalRef)) {
160 LOGE("plugin-ani get request call back failed");
161 AceFreeAsyncJSCallbackInfo(&asyncCallbackInfo);
162 return;
163 }
164 asyncCallbackInfo->cbInfo.callback = fnObjGlobalRef;
165 AceRequestCompleteAsyncCallbackWork(env, asyncCallbackInfo);
166 AceFreeAsyncJSCallbackInfo(&asyncCallbackInfo);
167 }
168
On(ani_env * env,ani_string eventTypeAni,ani_fn_object fnObj)169 static void On([[maybe_unused]] ani_env* env, [[maybe_unused]] ani_string eventTypeAni, ani_fn_object fnObj)
170 {
171 std::string eventType = AniStringToNativeString(env, eventTypeAni);
172 if (eventType != "push" && eventType != "request") {
173 LOGE("plugin-ani Unsupported event type %{public}s", eventType.c_str());
174 return;
175 }
176 ACEAsyncJSCallbackInfo* asyncCallbackInfo = AceCreateAsyncJSCallbackInfo(env);
177 asyncCallbackInfo->jsParamList.paramList.PutStringValue("eventName", eventType);
178 ani_ref fnObjGlobalRef = nullptr;
179 if (ANI_OK != env->GlobalReference_Create(reinterpret_cast<ani_ref>(fnObj), &fnObjGlobalRef)) {
180 LOGE("plugin-ani get %{public}s call back failed", eventType.c_str());
181 AceFreeAsyncJSCallbackInfo(&asyncCallbackInfo);
182 return;
183 }
184 asyncCallbackInfo->cbInfo.callback = fnObjGlobalRef;
185 CallBackType eventCallbackType = CallBackType::PushEvent;
186 if (eventType == "request") {
187 eventCallbackType = CallBackType::RequestEvent;
188 }
189 int32_t pid = IPCSkeleton::GetCallingPid();
190 asyncCallbackInfo->wantStage.SetBundle("plugin" + std::to_string(pid));
191 ANIPluginCallbackMgr::Instance().RegisterOnEvent(env, eventCallbackType, asyncCallbackInfo->wantStage,
192 asyncCallbackInfo->cbInfo);
193 AceFreeAsyncJSCallbackInfo(&asyncCallbackInfo);
194 }
195
196 } // namespace OHOS::Ace::Ani
ANI_Constructor(ani_vm * vm,uint32_t * result)197 ANI_EXPORT ani_status ANI_Constructor(ani_vm *vm, uint32_t *result)
198 {
199 ani_env* env;
200 if (ANI_OK != vm->GetEnv(ANI_VERSION_1, &env)) {
201 LOGE("plugin-ani Unsupported ANI_VERSION_1");
202 return ANI_ERROR;
203 }
204 ani_namespace ns;
205 if (ANI_OK != env->FindNamespace(ANI_PLUGINCOMPONENT_NS, &ns)) {
206 LOGE("plugin-ani Not found ns");
207 return ANI_ERROR;
208 }
209 std::array methods = {
210 ani_native_function {"pushNative", nullptr,
211 reinterpret_cast<void *>(OHOS::Ace::Ani::Push)},
212 ani_native_function {"requestNative", nullptr,
213 reinterpret_cast<void *>(OHOS::Ace::Ani::Request)},
214 ani_native_function {"on", nullptr,
215 reinterpret_cast<void *>(OHOS::Ace::Ani::On)},
216 };
217 if (ANI_OK != env->Namespace_BindNativeFunctions(ns, methods.data(), methods.size())) {
218 LOGE("plugin-ani Namespace_BindNativeFunctions error");
219 return ANI_ERROR;
220 }
221 *result = ANI_VERSION_1;
222 return ANI_OK;
223 }