Split Native Parts to SharedObject and Executable
[platform/core/dotnet/launcher.git] / NativeLauncher / src / waiter.cc
1
2 #include <poll.h>
3
4 #ifndef NO_TIZEN
5 #include <launchpad.h>
6 #include <aul.h>
7 #endif
8
9 #include <memory>
10 #include <vector>
11 #include <map>
12 #include <poll.h>
13
14 #include <iostream>
15
16 #include "waiter.h"
17 #include "log.h"
18
19 namespace dotnet {
20 namespace runtime {
21
22 struct FdHandler
23 {
24   pollfd *info;
25   Receiver receiver;
26 };
27
28 static volatile bool Waiting_;
29 static std::vector<pollfd> Fdlist_;
30 static std::map<int, FdHandler> Handlers_;
31 static Waiter::AppInfo AppInfo_;
32
33 void Waiter::OnPrepared()
34 {
35   if (!context.Prepare())
36   {
37     _DBG("Fail to Prepare...");
38   }
39 }
40
41 void Waiter::OnRequested(const AppInfo& info)
42 {
43   // do some job on user id is still system
44
45   if (!context.Request())
46   {
47     _DBG("Fail to Request...");
48   }
49 }
50
51 void Waiter::OnExecuted(const char *path, const char *app_root, int argc, char *argv[])
52 {
53   if (!context.Execute(path, app_root, argc, argv))
54   {
55     _DBG("Fail to Execute...");
56   }
57 }
58
59 void Waiter::OnWaiting()
60 {
61   // Start the loop
62   Waiting_ = true;
63
64   _DBG("start polling...");
65   while (Waiting_)
66   {
67     if (poll(Fdlist_.data(), Fdlist_.size(), -1) < 0)
68       continue;
69
70     for (auto &p : Fdlist_)
71     {
72       if ( (p.revents | POLLIN) != 0 )
73         Handlers_[p.fd].receiver(p.fd);
74     }
75   }
76   _DBG("end polling...");
77 }
78
79 void Waiter::Stop()
80 {
81   // Stop the loop
82
83   Waiting_ = false;
84 }
85
86
87 void Waiter::RegisterFd(int fd, Receiver receiver)
88 {
89   // register fd should be caught in event loop
90
91   _DBG("Register fd %d", fd);
92
93   pollfd info;
94   info.fd = fd;
95   info.events = POLLIN;
96   info.revents = 0;
97
98   FdHandler handler;
99   Fdlist_.push_back(info);
100   handler.info = &Fdlist_.back(); 
101   handler.receiver = receiver;
102
103   Handlers_[fd] = handler;
104 }
105
106 void Waiter::DeregisterFd(int fd)
107 {
108   // deregister fd should be caught in event loop
109   
110   pollfd *info = Handlers_[fd].info;
111   Fdlist_.erase(Fdlist_.begin() - (info - &Fdlist_.front()));
112   Handlers_.erase(fd);
113 }
114
115 int Waiter::WaitToLaunching(int argc, char *argv[])
116 {
117 #ifndef NO_TIZEN
118   auto on_create = [](bundle *extra, int type, void *user_data)
119   {
120     _DBG("on_create..."); // XXX
121     Waiter* waiter = static_cast<Waiter*>(user_data);
122     waiter->OnPrepared();
123   };
124
125   auto on_launch = [](int argc, char **argv, const char *app_path,
126       const char *appid, const char *pkgid,
127       const char *pkg_type, void *user_data) -> int
128   {
129     _DBG("on_launch..."); // XXX
130     Waiter* waiter = static_cast<Waiter*>(user_data);
131
132     _DBG ("app path : %s", app_path);
133     _DBG ("app id : %s", appid);
134     _DBG ("pkg id : %s", pkgid);
135     _DBG ("pkg type : %s", pkg_type);
136
137     AppInfo info = {
138       AppPath : app_path,
139       AppId : appid,
140       PkgId : pkgid,
141       PkgType : pkg_type
142     };
143
144     waiter->OnRequested(info);
145     return 0;
146   };
147
148   auto on_terminate = [](int argc, char **argv, void *user_data) -> int
149   {
150     _DBG("on_terminate..."); // XXX
151     
152     string app_root(aul_get_app_root_path());
153     Waiter* waiter = static_cast<Waiter*>(user_data);
154     waiter->OnExecuted(argv[0], app_root.c_str(), argc, argv);
155     return 0;
156   };
157
158   auto on_start_loop = [](void *user_data)
159   {
160     _DBG("on_start_loop..."); // XXX
161     Waiter* waiter = static_cast<Waiter*>(user_data);
162     waiter->OnWaiting();
163   };
164
165   auto on_quit_loop = [](void *user_data)
166   {
167     _DBG("on_quit_loop..."); // XXX
168     Waiter* waiter = static_cast<Waiter*>(user_data);
169     waiter->Stop();
170   };
171
172   auto on_add_fd = [](void *user_data, int fd, loader_receiver_cb receiver)
173   {
174     _DBG("on_add_fd..."); // XXX
175     Waiter* waiter = static_cast<Waiter*>(user_data);
176     waiter->RegisterFd(fd, receiver);
177   };
178
179   auto on_remove_fd = [](void *user_data, int fd)
180   {
181     _DBG("on_remove_fd..."); // XXX
182     Waiter* waiter = static_cast<Waiter*>(user_data);
183     waiter->DeregisterFd(fd);
184   };
185
186   _DBG("launcher wait..."); // XXX
187   loader_lifecycle_callback_s callbacks = {
188     .create = on_create,
189     .launch = on_launch,
190     .terminate = on_terminate
191   };
192
193         loader_adapter_s adapter = {
194                 .loop_begin = on_start_loop,
195                 .loop_quit = on_quit_loop,
196                 .add_fd = on_add_fd,
197                 .remove_fd = on_remove_fd
198         };
199
200   return launchpad_loader_main(argc, argv, &callbacks, &adapter, this);
201 #else
202   if (argc < 2)
203   {
204     _DBG("not enough args : %d", argc);
205     return -1;
206   }
207   _DBG("argv[1] = %s", argv[1]);
208   std::string app_path(argv[1]);
209   std::string app_root;
210   auto pos = app_path.find_last_of('/');
211   if (pos != std::string::npos)
212     app_root = app_path.substr(0, pos);
213   else
214     app_root = ".";
215
216   this->OnPrepared();
217   AppInfo info = {
218     AppPath : argv[1],
219     AppId : "",
220     PkgId : "",
221     PkgType : ""
222   };
223   this->OnRequested(info);
224   this->OnExecuted(app_path.c_str(), app_root.c_str(), argc, argv);
225 #endif
226 }
227
228 void Waiter::SetContext(WaiterContext ctx)
229 {
230   context = ctx;
231 }
232
233 WaiterContext::WaiterContext()
234 {
235   Step = Status::Started;
236 }
237
238 bool WaiterContext::Prepare()
239 {
240   if (Step == Status::Started && Prepared != nullptr && Prepared(Data) == 0)
241   {
242     Step = Status::Prepared;
243     return true;
244   }
245   return false;
246 }
247
248 bool WaiterContext::Request()
249 {
250   if (Step == Status::Prepared && Requested != nullptr && Requested(Data) == 0)
251   {
252     Step = Status::Requested;
253     return true;
254   }
255   return false;
256 }
257
258 bool WaiterContext::Execute(const char *path, const char *app_root, int argc, char *argv[])
259 {
260   if (Step == Status::Requested && Executed != nullptr &&
261       Executed(path, app_root, argc, argv, Data))
262   {
263     Step = Status::Executed;
264     return true;
265   }
266   return false;
267 }
268
269 }  // namespace runtime
270 }  // namespace dotnet
271
272 using dotnet::runtime::Waiter;
273 using dotnet::runtime::WaiterContext;
274
275 static Waiter waiter;
276
277 void register_launching_callback(prepared_callback prepared,
278     requested_callback requested, executed_callback executed, void *data)
279 {
280   WaiterContext context;
281   context.Prepared = prepared;
282   context.Requested = requested;
283   context.Executed = executed;
284   context.Data = data;
285
286   waiter.SetContext(context);
287 }
288
289 void wait_for_launching(int argc, char *argv[])
290 {
291   _DBG("wait_for_launching...");
292
293   waiter.WaitToLaunching(argc, argv);
294 }
295