• 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 "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