1 /*
2 * Copyright (c) 2020 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 "ability_thread.h"
17
18 #include <ability.h>
19 #include <ability_kit_command.h>
20 #include <ability_service_interface.h>
21 #include <ability_state.h>
22 #include <climits>
23 #include <cstring>
24 #ifdef ABILITY_WINDOW_SUPPORT
25 #include <common/graphic_startup.h>
26 #include <common/task_manager.h>
27 #include <dock/screen_device_proxy.h>
28 #include <font/ui_font_header.h>
29 #include <sys/prctl.h>
30 #endif
31 #include <dlfcn.h>
32 #include <kvstore_env.h>
33
34 #include "ability_env.h"
35 #include "ability_env_impl.h"
36 #include "ability_info.h"
37 #include "ability_loader.h"
38 #include "ability_service_interface.h"
39 #include "adapter.h"
40 #include "element_name_utils.h"
41 #include "ipc_skeleton.h"
42 #include "log.h"
43 #include "rpc_errno.h"
44
45 namespace OHOS {
46 namespace {
47 constexpr static char PATH_SEPARATOR[] = "/";
48 constexpr static char LIB_PREFIX[] = "/lib";
49 constexpr static char LIB_SUFFIX[] = ".so";
50 constexpr static char ACE_ABILITY_NAME[] = "AceAbility";
51 #ifdef ABILITY_WINDOW_SUPPORT
52 #ifdef OPENHARMONY_FONT_PATH
53 constexpr static char FONT_PATH[] = "/storage/data/";
54 #else
55 constexpr static char FONT_PATH[] = "/sdcard/data/";
56 #endif
57 constexpr static int UI_TASK_HANDLER_PERIOD = 10 * 1000; // UI task execute period is 10ms
58 constexpr static char UI_TASK_THREAD_NAME[] = "UITaskPost";
59 static uint32_t g_fontPsramBaseAddr[MIN_FONT_PSRAM_LENGTH / 4];
60 #endif
61 }
62 bool AbilityThread::isAppRunning_ = true;
63 bool AbilityThread::isNativeApp_ = true;
64 bool AbilityThread::isDisplayInited_ = false;
65
~AbilityThread()66 AbilityThread::~AbilityThread()
67 {
68 AdapterFree(identity_);
69 delete abilityScheduler_;
70 abilityScheduler_ = nullptr;
71 delete eventHandler_;
72 eventHandler_ = nullptr;
73 }
74
ThreadMain(uint64_t token)75 void AbilityThread::ThreadMain(uint64_t token)
76 {
77 HILOG_INFO(HILOG_MODULE_APP, "AbilityThread::ThreadMain enter");
78
79 AbilityThread abilityThread;
80 abilityThread.AttachBundle(token);
81
82 HILOG_INFO(HILOG_MODULE_APP, "AbilityThread::ThreadMain start loop");
83 abilityThread.Run();
84 }
85
86 #ifdef ABILITY_WINDOW_SUPPORT
UITaskPost(void * arg)87 void *AbilityThread::UITaskPost(void *arg)
88 {
89 prctl(PR_SET_NAME, UI_TASK_THREAD_NAME);
90
91 auto handler = static_cast<AbilityEventHandler *>(arg);
92 if (handler == nullptr) {
93 HILOG_ERROR(HILOG_MODULE_APP, "EventHandler is nullptr, fail to start loop");
94 return nullptr;
95 }
96
97 int ret = pthread_detach(pthread_self());
98 if (ret != 0) {
99 HILOG_WARN(HILOG_MODULE_APP, "UITaskPost detach failed: %{public}d", ret);
100 }
101
102 HILOG_INFO(HILOG_MODULE_APP, "start UITaskPost loop");
103 while (isAppRunning_) {
104 handler->PostTask([] {
105 TaskManager::GetInstance()->TaskHandler();
106 });
107 usleep(UI_TASK_HANDLER_PERIOD);
108 }
109 return nullptr;
110 }
111
InitUITaskEnv()112 void AbilityThread::InitUITaskEnv()
113 {
114 if (isDisplayInited_) {
115 return;
116 }
117
118 HILOG_INFO(HILOG_MODULE_APP, "Hal and UI init");
119 GraphicStartUp::Init();
120 GraphicStartUp::InitFontEngine(reinterpret_cast<uintptr_t>(g_fontPsramBaseAddr), MIN_FONT_PSRAM_LENGTH,
121 const_cast<char *>(FONT_PATH), DEFAULT_VECTOR_FONT_FILENAME);
122 auto screenDevice = new ScreenDevice();
123 ScreenDeviceProxy::GetInstance()->SetDevice(screenDevice);
124
125 HILOG_INFO(HILOG_MODULE_APP, "Create UITaskPost thread");
126 pthread_t tid;
127 int ret = pthread_create(&tid, nullptr, AbilityThread::UITaskPost, eventHandler_);
128 if (ret != 0) {
129 HILOG_ERROR(HILOG_MODULE_APP, "create UI post thread error, %{public}d", ret);
130 exit(-1);
131 }
132 isDisplayInited_ = true;
133 }
134 #endif
135
StartAbilityCallback(const Want & want)136 void AbilityThread::StartAbilityCallback(const Want &want)
137 {
138 if ((want.sid == nullptr) || (want.element == nullptr)) {
139 return;
140 }
141 HILOG_INFO(HILOG_MODULE_APP, "start ability callback");
142 IpcIo io;
143 char data[MAX_IO_SIZE];
144 IpcIoInit(&io, data, MAX_IO_SIZE, 0);
145 if (!SerializeElement(&io, want.element)) {
146 return;
147 }
148 WriteInt32(&io, EC_SUCCESS);
149 MessageOption option;
150 MessageOptionInit(&option);
151 option.flags = TF_OP_ASYNC;
152 if (SendRequest(*(want.sid), SCHEDULER_APP_INIT, &io, nullptr, option, nullptr) != ERR_NONE) {
153 HILOG_ERROR(HILOG_MODULE_APP, "start ability callback failed, ipc error");
154 }
155 }
156
PerformAppInit(const AppInfo & appInfo)157 void AbilityThread::PerformAppInit(const AppInfo &appInfo)
158 {
159 HILOG_INFO(HILOG_MODULE_APP, "Start app init");
160 if ((appInfo.bundleName.empty()) || (appInfo.srcPath.empty())) {
161 HILOG_ERROR(HILOG_MODULE_APP, "appInfo is null");
162 return;
163 }
164 if (!appInfo.isNativeApp && (appInfo.moduleNames.size() != 1)) {
165 HILOG_ERROR(HILOG_MODULE_APP, "only native app support multi hap");
166 return;
167 }
168 AbilityEnvImpl::GetInstance().SetAppInfo(appInfo);
169 AbilityThread::isNativeApp_ = appInfo.isNativeApp;
170
171 for (const auto &module : appInfo.moduleNames) {
172 if (appInfo.isNativeApp) {
173 std::string modulePath = appInfo.srcPath + PATH_SEPARATOR + module + LIB_PREFIX + module + LIB_SUFFIX;
174 if (modulePath.size() > PATH_MAX) {
175 continue;
176 }
177 char realPath[PATH_MAX + 1] = { 0 };
178 if (realpath(modulePath.c_str(), realPath) == nullptr) {
179 HILOG_ERROR(HILOG_MODULE_APP, "Fail to get realpath of %{public}s", modulePath.c_str());
180 continue;
181 }
182 void *handle = dlopen(static_cast<char *>(realPath), RTLD_NOW | RTLD_GLOBAL);
183 if (handle == nullptr) {
184 HILOG_ERROR(HILOG_MODULE_APP, "Fail to dlopen %{public}s, [%{public}s]", modulePath.c_str(), dlerror());
185 exit(-1);
186 }
187 handle_.emplace_front(handle);
188 }
189 }
190
191 int ret = UtilsSetEnv(GetDataPath());
192 HILOG_INFO(HILOG_MODULE_APP, "Set env ret: %{public}d, App init end", ret);
193 }
194
PerformAppExit()195 void AbilityThread::PerformAppExit()
196 {
197 HILOG_INFO(HILOG_MODULE_APP, "perform app exit");
198 if (eventHandler_ == nullptr) {
199 return;
200 }
201
202 eventHandler_->PostTask([] {
203 AbilityThread::isAppRunning_ = false;
204 });
205 for (auto handle : handle_) {
206 dlclose(handle);
207 }
208 eventHandler_->PostQuit();
209 handle_.clear();
210 }
211
PerformTransactAbilityState(const Want & want,int state,uint64_t token,int abilityType)212 void AbilityThread::PerformTransactAbilityState(const Want &want, int state, uint64_t token, int abilityType)
213 {
214 HILOG_INFO(HILOG_MODULE_APP, "perform transact ability state to [%{public}d]", state);
215 Ability *ability = nullptr;
216 auto iter = abilities_.find(token);
217 if ((iter == abilities_.end()) || (iter->second == nullptr)) {
218 if (want.element == nullptr) {
219 HILOG_ERROR(HILOG_MODULE_APP, "element name is null, fail to load ability");
220 AbilityMsClient::GetInstance().SchedulerLifecycleDone(token, STATE_INITIAL);
221 return;
222 }
223 auto abilityName = isNativeApp_ ? want.element->abilityName : ACE_ABILITY_NAME;
224 ability = AbilityLoader::GetInstance().GetAbilityByName(abilityName);
225 if (ability == nullptr) {
226 HILOG_ERROR(HILOG_MODULE_APP, "fail to load ability: %{public}s", abilityName);
227 AbilityMsClient::GetInstance().SchedulerLifecycleDone(token, STATE_INITIAL);
228 return;
229 }
230 HILOG_INFO(HILOG_MODULE_APP, "Create ability success [%{public}s]", want.element->abilityName);
231
232 // Only page ability need to init display
233 #ifdef ABILITY_WINDOW_SUPPORT
234 if (abilityType == PAGE) {
235 InitUITaskEnv();
236 }
237 #endif
238 ability->Init(token, abilityType, AbilityThread::isNativeApp_);
239 abilities_[token] = ability;
240 } else {
241 ability = iter->second;
242 }
243
244 if (ability->GetState() != state) {
245 HandleLifecycleTransaction(*ability, want, state);
246 }
247
248 HILOG_INFO(HILOG_MODULE_APP, "perform transact ability state done [%{public}d]", ability->GetState());
249 AbilityMsClient::GetInstance().SchedulerLifecycleDone(token, ability->GetState());
250 if (ability->GetState() == STATE_ACTIVE) {
251 StartAbilityCallback(want);
252 }
253
254 if (ability->GetState() == STATE_INITIAL) {
255 abilities_.erase(token);
256 delete ability;
257 }
258 }
259
PerformConnectAbility(const Want & want,uint64_t token)260 void AbilityThread::PerformConnectAbility(const Want &want, uint64_t token)
261 {
262 auto iter = abilities_.find(token);
263 if (iter == abilities_.end() || iter->second == nullptr) {
264 HILOG_ERROR(HILOG_MODULE_APP, "app has been stopped");
265 return;
266 }
267 const SvcIdentity *sid = iter->second->OnConnect(want);
268 AbilityMsClient::GetInstance().ScheduleAms(nullptr, token, sid, CONNECT_ABILITY_DONE);
269 }
270
PerformDisconnectAbility(const Want & want,uint64_t token)271 void AbilityThread::PerformDisconnectAbility(const Want &want, uint64_t token)
272 {
273 auto iter = abilities_.find(token);
274 if (iter == abilities_.end() || iter->second == nullptr) {
275 HILOG_ERROR(HILOG_MODULE_APP, "app has been stopped");
276 return;
277 }
278 iter->second->OnDisconnect(want);
279 AbilityMsClient::GetInstance().ScheduleAms(nullptr, token, nullptr, DISCONNECT_ABILITY_DONE);
280 }
281
PerformDumpAbility(const Want & want,uint64_t token)282 void AbilityThread::PerformDumpAbility(const Want &want, uint64_t token)
283 {
284 auto iter = abilities_.find(token);
285 if (iter == abilities_.end() || iter->second == nullptr) {
286 HILOG_ERROR(HILOG_MODULE_APP, "app has been stopped");
287 return;
288 }
289 if (want.sid == nullptr) {
290 HILOG_ERROR(HILOG_MODULE_APP, "SvcIdentity is null, dump failed");
291 return;
292 }
293 std::string extra("");
294 if (want.data != nullptr) {
295 auto str = static_cast<char *>(want.data);
296 if (want.dataLength == strlen(str) + 1) {
297 extra = str;
298 }
299 }
300 iter->second->Dump(extra);
301 std::string dumpInfo = iter->second->GetDumpInfo();
302 IpcIo io;
303 char data[MAX_IO_SIZE];
304 IpcIoInit(&io, data, MAX_IO_SIZE, 1);
305 WriteString(&io, dumpInfo.c_str());
306 MessageOption option;
307 MessageOptionInit(&option);
308 option.flags = TF_OP_ASYNC;
309 if (SendRequest(*(want.sid), SCHEDULER_DUMP_ABILITY, &io, nullptr, option, nullptr) != ERR_NONE) {
310 HILOG_ERROR(HILOG_MODULE_APP, "dump ability failed, ipc error");
311 }
312 ReleaseSvc(*(want.sid));
313 }
314
HandleLifecycleTransaction(Ability & ability,const Want & want,int state)315 void AbilityThread::HandleLifecycleTransaction(Ability &ability, const Want &want, int state)
316 {
317 // Switch INITIAL state to INACTIVE state
318 if (ability.GetState() == STATE_INITIAL) {
319 ability.OnStart(want);
320 }
321
322 // Switch ACTIVE state to INACTIVE state
323 if (ability.GetState() == STATE_ACTIVE) {
324 ability.OnInactive();
325 }
326
327 switch (state) {
328 case STATE_INITIAL: {
329 if (ability.GetState() == STATE_INACTIVE) {
330 ability.OnBackground();
331 }
332 ability.OnStop();
333 break;
334 }
335 case STATE_INACTIVE: {
336 // Not support transact from BACKGROUND to INACTIVE state
337 break;
338 }
339 case STATE_ACTIVE: {
340 ability.OnActive(want);
341 break;
342 }
343 case STATE_BACKGROUND: {
344 if (ability.GetState() == STATE_INACTIVE) {
345 ability.OnBackground();
346 }
347 break;
348 }
349 default: {
350 HILOG_ERROR(HILOG_MODULE_APP, "Unknown target state: %{public}d", state);
351 break;
352 }
353 }
354 }
355
AttachBundle(uint64_t token)356 void AbilityThread::AttachBundle(uint64_t token)
357 {
358 eventHandler_ = new AbilityEventHandler();
359 abilityScheduler_ = new AbilityScheduler(*eventHandler_, *this);
360 if (!AbilityMsClient::GetInstance().Initialize()) {
361 HILOG_ERROR(HILOG_MODULE_APP, "ams feature is null");
362 return;
363 }
364
365 identity_ = static_cast<SvcIdentity *>(AdapterMalloc(sizeof(SvcIdentity)));
366 if (identity_ == nullptr) {
367 HILOG_ERROR(HILOG_MODULE_APP, "ams identity is null");
368 return;
369 }
370
371 objectStub_.func = AbilityScheduler::AmsCallback;
372 objectStub_.args = (void*)abilityScheduler_;
373 objectStub_.isRemote = false;
374 identity_->handle = IPC_INVALID_HANDLE;
375 identity_->token = SERVICE_TYPE_ANONYMOUS;
376 identity_->cookie = reinterpret_cast<uintptr_t>(&objectStub_);
377 AbilityMsClient::GetInstance().ScheduleAms(nullptr, token, identity_, ATTACH_BUNDLE);
378 }
379
Run()380 void AbilityThread::Run()
381 {
382 if (eventHandler_) {
383 eventHandler_->Run();
384 }
385 }
386 } // namespace OHOS
387