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