YSTest: AndroidHost.cpp 源文件

YSTest PreAlpha_b900_20201012 The YSLib Test Project

AndroidHost.cpp
浏览该文件的文档.
1 /*
2 © 2014-2016, 2019 FrankHB.
3
4 This file is part of the YSLib project, and may only be used,
5 modified, and distributed under the terms of the YSLib project
6 license, LICENSE.TXT. By continuing to use, modify, or distribute
7 this file you indicate that you have read the license and
8 understand and accept it fully.
9 */
10
29 #include "Helper/YModules.h"
30 #include YFM_Android_Helper_AndroidHost // for platform::RetryOnInterrupted;
31 #if YCL_Android
32 # include <android/configuration.h>
33 # include "AndroidScreen.h"
34 #endif
35 #include YFM_YSLib_UI_YDesktop
36 #include YFM_Helper_GUIApplication // for YSLib::LockInstance,
37 // YSLib::PostMessage;
38
39 #if YCL_Android
40
41 namespace YSLib
42 {
43
44 using namespace Drawing;
45 using namespace Host;
46
47 namespace
48 {
49
51 Android::NativeHost* NativeAppHostPtr{};
52
53 } // unnamed namespace;
54
55 namespace Android
56 {
57
58 NativeHost::NativeHost(::ANativeActivity& ac, void* saved_state,
59 size_t state_size)
60 : activity(ac), p_config(::AConfiguration_new()),
61 looper(FetchNativeLooper({})), msg_pipe(platform_ex::MakePipe()),
62 p_screen()
63 {
64 NativeAppHostPtr = this;
65 YAssert(NativeAppHostPtr, "Duplicate instance found.");
66
67 auto& cb(Deref(ac.callbacks));
68
69 # define YCL_Android_RegCb_Begin(_n, ...) \
70 cb.on##_n = [](__VA_ARGS__){ \
71 YTraceDe(Debug, "ANativeActivity::" #_n ": %p.", \
72 ystdex::pvoid(Nonnull(p_activity)));
73 #define YCL_Android_RegSimpCb(_n, ...) \
74 YCL_Android_RegCb_Begin(_n, ::ANativeActivity* p_activity) \
75 __VA_ARGS__; \
76 }
77 # define YCL_NativeHostPtr static_cast<NativeHost*>(p_activity->instance)
78 yunseq
79 (
80 YCL_Android_RegSimpCb(Destroy, delete YCL_NativeHostPtr),
81 YCL_Android_RegSimpCb(Start, void()),
82 YCL_Android_RegCb_Begin(Resume, ::ANativeActivity* p_activity)
83 YTraceDe(Debug, " Application resumed.");
84 YCL_NativeHostPtr->ReleaseSavedState();
85 YCL_NativeHostPtr->paused = {};
86 },
87 YCL_Android_RegCb_Begin(SaveInstanceState,
88 ::ANativeActivity* p_activity, ::size_t* p_len)
89 return YCL_NativeHostPtr->SaveInstanceState(p_len);
90 },
91 YCL_Android_RegCb_Begin(Pause, ::ANativeActivity* p_activity)
92 YTraceDe(Debug, " Application paused.");
93 YCL_NativeHostPtr->paused = true;
94 },
95 // YCL_Android_RegSimpCb(Stop, void()),
96 YCL_Android_RegSimpCb(ConfigurationChanged,
97 YCL_NativeHostPtr->LoadConfiguration()),
98 // YCL_Android_RegSimpCb(LowMemory, void()),
99 YCL_Android_RegCb_Begin(WindowFocusChanged,
100 ::ANativeActivity* p_activity, int focused)
101 YTraceDe(Debug, " focused = %d.", focused);
102 },
103 YCL_Android_RegCb_Begin(NativeWindowResized,
104 ::ANativeActivity* p_activity, ::ANativeWindow* p_window)
105 YTraceDe(Debug, " p_window = %p.", ystdex::pvoid(p_window));
106 auto& host(*YCL_NativeHostPtr);
107
108 if(!host.thrdMain.joinable())
109 {
110 YTraceDe(Debug, "Starting native main thread...");
111 host.thrdMain = std::thread([&host, p_activity, p_window]{
112 host.p_screen.reset(new Devices::AndroidScreen(*p_window));
113 host.MainReturnValue = ::y_android_main();
114 YTraceDe(Debug, "Application main routine exited.");
115 ::ANativeActivity_finish(p_activity);
116 host.RunOnUIThread([]{
117 YTraceDe(Notice, "Finish method called.");
118 });
119 YTraceDe(Debug, "Clearing screen pointer...");
120 host.p_screen.reset();
121 YTraceDe(Informative, "Native main thread finished.");
122 });
123 }
124 else
125 YTraceDe(Err, "Native main thread already running.");
126 },
127 YCL_Android_RegCb_Begin(NativeWindowDestroyed,
128 ::ANativeActivity* p_activity, ::ANativeWindow* p_window)
129 YTraceDe(Debug, " p_window = %p.", ystdex::pvoid(p_window));
130
131 auto& host(*YCL_NativeHostPtr);
132
133 // TODO: Nonull?
134 if(const auto p_app = LockInstance())
135 {
136 // XXX: Use proper exit code.
137 PostQuitMessage(0);
138 YTraceDe(Debug, "YSLib quit message posted.");
139 }
140 YTraceDe(Informative,
141 "Waiting for native main thread finishing...");
142 FilterExceptions(std::bind(&std::thread::join, std::ref(
143 host.thrdMain)), "AndroidHost NativeWindowDestroyed handler");
144 YTraceDe(Informative, "Waiting for screen being released...");
145 YTraceDe(Debug, "Client thread terminated.");
146 },
147 YCL_Android_RegCb_Begin(InputQueueCreated,
148 ::ANativeActivity* p_activity, ::AInputQueue* p_queue)
149 YTraceDe(Debug, " p_queue = %p.", ystdex::pvoid(p_queue));
150
151 auto& host(*YCL_NativeHostPtr);
152
153 host.p_input_queue.reset(
154 new InputQueue(host.looper, Deref(p_queue)));
155 },
156 YCL_Android_RegCb_Begin(InputQueueDestroyed,
157 ::ANativeActivity* p_activity, ::AInputQueue* p_queue)
158 YTraceDe(Debug, " p_queue = %p.", ystdex::pvoid(p_queue));
159 YCL_NativeHostPtr->p_input_queue.reset();
160 }
161 );
162 # undef YCL_NativeHostPtr
163 # undef YCL_Android_RegSimpCb
164 # undef YCL_Android_RegCb_Begin
165 if(saved_state && state_size != 0)
166 {
167 const auto p_src(static_cast<const byte*>(saved_state));
168
169 YTraceDe(Debug, "Saved state needed to be stored.");
170 vecSavedState = vector<byte>(p_src, p_src + state_size);
171 YTraceDe(Debug, "Saved state cloned.");
172 }
173 YTraceDe(Debug, "Loading configuration...");
174 LoadConfiguration();
175 YTraceDe(Debug, "Adding file descriptor for UI thread call...");
176 ::ALooper_addFd(&looper.get(), *msg_pipe.first.get(), ALOOPER_POLL_CALLBACK,
177 ALOOPER_EVENT_INPUT, [](int, int, void* p_data){
178 auto& host(Deref(static_cast<NativeHost*>(p_data)));
179 lock_guard<mutex> lck(host.msg_mutex);
180 auto& task(host.msg_task);
181 int ret;
182 const int res(read(*host.msg_pipe.first.get(), &ret, sizeof(int)));
183
184 if(res < 0)
185 YTraceDe(Warning, "Failed reading file descriptor.");
186 else if(res != sizeof(int))
187 YTraceDe(Warning, "Truncated reading with result %d.", res);
188 if(task)
189 {
190 task();
191 task = nullptr;
192 }
193 return 1;
194 }, this);
195 YTraceDe(Debug, "Native host launched.");
196 }
197 NativeHost::~NativeHost()
198 {
199 ::ALooper_removeFd(&looper.get(), *msg_pipe.first.get());
200 YTraceDe(Debug, "File descriptor for UI thread call removed.");
201 ReleaseSavedState();
202 YTraceDe(Debug, "State released.");
203 p_input_queue.reset();
204 YTraceDe(Debug, "Input queue detached.");
205 p_config.reset();
206 YTraceDe(Debug, "Native host terminated.");
207 }
208
209 Devices::Screen&
210 NativeHost::GetHostScreenRef() const ynothrow
211 {
212 // TODO: Expose screen type and use %GetScreenRef instead.
213 return Deref(p_screen);
214 }
215
216 void
217 NativeHost::ClearSavedStateHandler()
218 {
219 lock_guard<mutex> lck(state_mutex);
220
221 fSaveState = nullptr;
222 }
223
224 void
225 NativeHost::LoadConfiguration()
226 {
227 ::AConfiguration_fromAssetManager(Nonnull(p_config).get(),
228 activity.get().assetManager);
229 TraceConfiguration(*p_config);
230 YTraceDe(Debug, "Configuration loaded.");
231 }
232
233 void
234 NativeHost::ReleaseSavedState() ynothrow
235 {
236 lock_guard<mutex> lck(state_mutex);
237
238 vecSavedState.clear();
239 }
240
241 void
242 NativeHost::ResizeScreen(const Drawing::Size& s)
243 {
244 Deref(p_screen).SetSize(s);
245 }
246
247 void
248 NativeHost::RestoreSavedState(byte* p_byte) const
249 {
250 lock_guard<mutex> lck(state_mutex);
251
252 std::copy_n(vecSavedState.cbegin(), vecSavedState.size(), Nonnull(p_byte));
253 }
254
255 void
256 NativeHost::RunOnUIThread(function<void()> f)
257 {
258 YTraceDe(Debug, "RunOnUIThread called.");
259
260 lock_guard<mutex> lck(msg_mutex);
261
262 msg_task = f;
263
264 int res(platform::RetryOnInterrupted([this]{
265 const int ret(1);
266
267 return ::write(*msg_pipe.second.get(), &ret, sizeof(int));
268 }));
269
270 if(res < 0)
271 YTraceDe(Warning, "Failed writing file descriptor, error = %d.",
272 errno);
273 else if(size_t(res) != sizeof(int))
274 YTraceDe(Warning, "Truncated writing with result %d.", int(res));
275 }
276
277 void*
278 NativeHost::SaveInstanceState(size_t* p_len)
279 {
280 void* p_saved_state = {};
281
282 {
283 lock_guard<mutex> lck(state_mutex);
284
285 if(fSaveState)
286 fSaveState(p_saved_state, *p_len);
287 vecSavedState.clear();
288 }
289 return p_saved_state;
290 }
291
292
293 NativeHost&
294 FetchNativeHostInstance() ynothrow
295 {
296 return Deref(NativeAppHostPtr);
297 }
298
299 ::ANativeWindow&
300 FetchDefaultWindow() ynothrow
301 {
302 return FetchNativeHostInstance().GetScreenRef().GetWindowRef();
303 }
304
305 } // namespace Android;
306
307 } // namespace YSLib;
308
309 extern "C" void
310 ANativeActivity_onCreate(::ANativeActivity* p_activity,
311 void* saved_state, ::size_t saved_state_size)
312 {
313 using namespace YSLib;
314 using namespace YSLib::Android;
315
316 YTraceDe(Debug, "Creating activity: %p.",
317 ystdex::pvoid(Nonnull(p_activity)));
318 p_activity->instance = make_unique<NativeHost>(*p_activity, saved_state,
319 saved_state_size).release();
320 }
321
322 #endif
323
platform::Nonnull
YB_PURE _type && Nonnull(_type &&p) ynothrowv
断言并返回非空参数。
Definition: Debug.h:518
platform_ex::Android::TraceConfiguration
YF_API void TraceConfiguration(::AConfiguration &, platform::Logger::Level=platform::Descriptions::Notice)
YSLib::PostQuitMessage
YF_API void PostQuitMessage(int=0, Messaging::Priority p=DefaultQuitPriority)
以指定错误码和优先级发起 Shell 终止请求。
Definition: YApplication.cpp:87
platform::RetryOnInterrupted
_type RetryOnInterrupted(_func f)
循环可能被中断的操作。
Definition: YCommon.h:373
YModules.h
Helper 库模块配置文件。
CHRLib::f
f(d, s)
YAssert
#define YAssert(_expr, _msg)
Definition: cassert.h:154
platform::Descriptions::Notice
@ Notice
Definition: YCommon.h:184
platform::Descriptions::Informative
@ Informative
Definition: YCommon.h:185
YSLib::LockInstance
YF_API locked_ptr< yimpl(GUIApplication), recursive_mutex > LockInstance()
锁定实例。
Definition: GUIApplication.cpp:301
yunseq
#define yunseq
无序列依赖表达式组求值。
Definition: ydef.h:1535
YTraceDe
#define YTraceDe(...)
YCLib 默认调试跟踪。
Definition: Debug.h:407
YSLib::FilterExceptions
bool FilterExceptions(_func f, const char *desc={}, RecordLevel lv=Alert, ExceptionTracer trace=ExtractAndTrace) ynothrow
调用函数并过滤宿主异常。
Definition: YException.h:225
platform::Descriptions::Err
@ Err
Definition: YCommon.h:182
platform::Descriptions::Warning
@ Warning
Definition: YCommon.h:183
YSLib
YSLib 命名空间。
Definition: AndroidHost.h:46
CHRLib::s
_tDst const _tSrc * s
Definition: CharacterProcessing.h:143
ystdex::pvoid
enable_if_t< or_< is_object< _type >, is_void< _type > >::value, void * > pvoid(_type *p)
取 void* 类型的指针。
Definition: addressof.hpp:166
YSLib::LoadConfiguration
YF_API ValueNode LoadConfiguration(bool={})
载入默认配置。
Definition: Initialization.cpp:730
platform::Deref
YB_PURE yconstfn auto Deref(_type &&p) -> decltype(*p)
断言并解引用非空指针。
Definition: Debug.h:547
platform_ex::Android::FetchNativeLooper
YF_API ::ALooper & FetchNativeLooper(bool)
取当前线程的本机消息循环。
platform::KeyCodes::DS::Start
@ Start
Definition: Keys.h:219
ystdex::write
std::basic_ostream< _tChar, typename _tString::traits_type > & write(std::basic_ostream< _tChar, typename _tString::traits_type > &os, const _tString &str, typename _tString::size_type pos=0, typename _tString::size_type n=_tString::npos)
非格式输出。
Definition: string.hpp:1761
platform::KeyCodes::DS::Pause
@ Pause
Definition: Keys.h:257
const
const Decapsulate const Decapsulate &y ynothrow ContextNode &ctx const
Definition: NPLA1Forms.cpp:1629
ynothrow
#define ynothrow
YSLib 无异常抛出保证：若支持 noexcept 关键字， 指定特定的 noexcept 异常规范。
Definition: ydef.h:1199
NPL::get
PDefH(void, LiftTermRef, TermNode &term, const TermNode &tm) ImplExpr(NPL ref get()
Definition: NPLA.h:1737
ystdex::ref
void ref(const _type &&)=delete
platform::Descriptions::Debug
@ Debug
Definition: YCommon.h:186
AndroidScreen.h
Android 屏幕。