• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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