|
1 /* |
|
2 * Copyright (c) 1999-2001 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * This component and the accompanying materials are made available |
|
5 * under the terms of "Eclipse Public License v1.0" |
|
6 * which accompanies this distribution, and is available |
|
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 * |
|
9 * Initial Contributors: |
|
10 * Nokia Corporation - initial contribution. |
|
11 * |
|
12 * Contributors: |
|
13 * |
|
14 * Description: |
|
15 * |
|
16 */ |
|
17 |
|
18 #include <eikenv.h> |
|
19 #include <eikappui.h> |
|
20 #include <eiksrvc.h> |
|
21 #include <stdio.h> |
|
22 |
|
23 #include "JesServer.h" |
|
24 #include "CJavaEventServer.h" |
|
25 |
|
26 |
|
27 |
|
28 const TInt KMaxUserName=64; |
|
29 const TInt KMaxJesName=3+1+8+1+KMaxUserName+1+8; |
|
30 |
|
31 |
|
32 class TJesName : public TBuf<KMaxJesName> |
|
33 { |
|
34 public: |
|
35 TJesName(const TDesC& aUserName); |
|
36 TJesName(const TDesC& aUserName,TInt aHandle); |
|
37 private: |
|
38 void Build(const TDesC& aUserName); |
|
39 }; |
|
40 |
|
41 class TJesParam : public MEventServer |
|
42 { |
|
43 public: |
|
44 virtual void Started(TInt aError, RServer2 aServer) |
|
45 { |
|
46 iServerHandle = aServer; |
|
47 iThread.RequestComplete(iStatus,aError); |
|
48 } |
|
49 virtual TAny* Arg() const |
|
50 { |
|
51 return iArg; |
|
52 } |
|
53 public: |
|
54 RThread iThread; |
|
55 RServer2 iServerHandle; |
|
56 TRequestStatus* iStatus; |
|
57 TAny* iArg; |
|
58 }; |
|
59 |
|
60 class CJesSession : public CSession2 |
|
61 { |
|
62 class TExecute |
|
63 { |
|
64 public: |
|
65 inline TInt operator()() const; |
|
66 private: |
|
67 TInt(*iFunc)(TAny*,TAny*,TAny*,TAny*,TAny*,TAny*,TAny*,TAny*,TAny*); |
|
68 TAny* iParam[9]; |
|
69 }; |
|
70 private: |
|
71 void ServiceL(const RMessage2& aMessage); |
|
72 static TInt ExecuteTrap(const TExecute& aExecute); |
|
73 }; |
|
74 |
|
75 class CJesScheduler : public CActiveScheduler, public MJesShutdown |
|
76 { |
|
77 public: |
|
78 static TInt Create(RServer2& serverHandle); |
|
79 virtual void Shutdown(); |
|
80 private: |
|
81 CJesScheduler(); |
|
82 static void CreateL(RServer2& serverHandle); |
|
83 private: |
|
84 CJesServer iServer; |
|
85 }; |
|
86 |
|
87 // Class TJesName |
|
88 |
|
89 // The thread name is made up of the user name, the process Id and |
|
90 // the address of this object. |
|
91 |
|
92 _LIT(KName,"jes-"); |
|
93 |
|
94 TJesName::TJesName(const TDesC& aUserName) |
|
95 // |
|
96 // Construct the base Java Event Server name |
|
97 // |
|
98 { |
|
99 Build(aUserName); |
|
100 } |
|
101 |
|
102 TJesName::TJesName(const TDesC& aUserName,TInt aHandle) |
|
103 // |
|
104 // Construct the full Java Event Server name |
|
105 // |
|
106 { |
|
107 Build(aUserName); |
|
108 AppendNum(aHandle,EHex); |
|
109 } |
|
110 |
|
111 void TJesName::Build(const TDesC& aUserName) |
|
112 // |
|
113 // Create the base of the server name |
|
114 // |
|
115 { |
|
116 Copy(KName); |
|
117 TProcessId id(RProcess().Id()); |
|
118 AppendNum(*reinterpret_cast<TInt*>(&id),EHex); |
|
119 Append('-'); |
|
120 Append(aUserName); |
|
121 Append('@'); |
|
122 } |
|
123 |
|
124 |
|
125 // class RJess |
|
126 |
|
127 TInt RJess::Connect(RServer2& aServer) |
|
128 // |
|
129 // Establish an IPC session with the event server and share it |
|
130 // |
|
131 { |
|
132 TInt r=CreateSession(aServer, TVersion(), CJavaEventBase::ELastPriority + 1); |
|
133 if (r==KErrNone) |
|
134 { |
|
135 r=ShareAuto(); |
|
136 if (r!=KErrNone) |
|
137 Close(); |
|
138 } |
|
139 return r; |
|
140 } |
|
141 |
|
142 // class TJavaEventServer |
|
143 |
|
144 inline TJavaEventServer::TJavaEventServer(CJavaEventServer* aServer) |
|
145 :iServer(aServer) |
|
146 {} |
|
147 |
|
148 EXPORT_C TJavaEventServer TJavaEventServer::NewL(const TDesC& aName, TThreadFunction aServerThread, TAny* aServerArg) |
|
149 { |
|
150 return CJavaEventServer::NewL(aName, aServerThread, aServerArg, 0, 0); |
|
151 } |
|
152 |
|
153 EXPORT_C TJavaEventServer TJavaEventServer::NewL(const TDesC& aName, TThreadFunction aServerThread, TAny* aServerArg, |
|
154 TUint aStackSize, RAllocator* aHeap) |
|
155 { |
|
156 return CJavaEventServer::NewL(aName, aServerThread, aServerArg, aStackSize, aHeap); |
|
157 } |
|
158 |
|
159 EXPORT_C void TJavaEventServer::Shutdown() |
|
160 { |
|
161 iServer->Shutdown(); |
|
162 } |
|
163 |
|
164 // class CJesServer |
|
165 |
|
166 EXPORT_C CJesServer::CJesServer(MJesShutdown* aShutdown): |
|
167 // |
|
168 // The Java Event Server shares the session between all thread clients |
|
169 // |
|
170 CServer2(0,ESharableSessions) |
|
171 , iShutdown(aShutdown) |
|
172 { |
|
173 } |
|
174 |
|
175 CJesServer::~CJesServer() |
|
176 { |
|
177 } |
|
178 |
|
179 CSession2* CJesServer::NewSessionL(const TVersion& /*version*/, const RMessage2& /*message*/) const |
|
180 { |
|
181 return new(ELeave) CJesSession(); |
|
182 } |
|
183 |
|
184 void CJesServer::Shutdown() |
|
185 { |
|
186 iShutdown.Start(); |
|
187 } |
|
188 |
|
189 |
|
190 // class CJesScheduler |
|
191 CJesScheduler::CJesScheduler() |
|
192 : iServer(this) |
|
193 { |
|
194 } |
|
195 |
|
196 void CJesScheduler::Shutdown() |
|
197 { |
|
198 CActiveScheduler::Stop(); |
|
199 } |
|
200 |
|
201 void CJesScheduler::CreateL(RServer2& serverHandle) |
|
202 { |
|
203 CJesScheduler* s=new(ELeave) CJesScheduler; |
|
204 CActiveScheduler::Install(s); |
|
205 s->iServer.StartL(KNullDesC); |
|
206 serverHandle = s->iServer.Server(); |
|
207 } |
|
208 |
|
209 TInt CJesScheduler::Create(RServer2& serverHandle) |
|
210 // |
|
211 // Create the Java Event thread scheduler and server |
|
212 // |
|
213 { |
|
214 TRAPD(r,CreateL(serverHandle)); |
|
215 return r; |
|
216 } |
|
217 |
|
218 // java-side |
|
219 void CJavaEventServer::AddRef() |
|
220 { |
|
221 iMutex.Wait(); |
|
222 ++iRef; |
|
223 iMutex.Signal(); |
|
224 } |
|
225 |
|
226 // java-side |
|
227 void CJavaEventServer::RemoveRef() |
|
228 { |
|
229 iMutex.Wait(); |
|
230 if ((--iRef == 0) && iShutdown) |
|
231 { |
|
232 iSession.Shutdown(); |
|
233 } |
|
234 iMutex.Signal(); |
|
235 } |
|
236 |
|
237 // java-side - consider purging event queue. |
|
238 void CJavaEventServer::Shutdown() |
|
239 { |
|
240 iMutex.Wait(); |
|
241 iShutdown=ETrue; |
|
242 if (0 == iRef) |
|
243 { |
|
244 iSession.Shutdown(); |
|
245 } |
|
246 iMutex.Signal(); |
|
247 } |
|
248 |
|
249 TInt CJavaEventServer::ServerThread(TAny* aParam) |
|
250 // |
|
251 // The thread function for the Java event server thread |
|
252 // This initialises the thread environment before reporting success |
|
253 // and then starting its scheduler |
|
254 // |
|
255 { |
|
256 MEventServer* server = static_cast<MEventServer*>(aParam); |
|
257 |
|
258 TInt err = KErrNoMemory; |
|
259 |
|
260 RServer2 serverHandle; |
|
261 |
|
262 CTrapCleanup* cleanup = CTrapCleanup::New(); |
|
263 if (cleanup) |
|
264 { |
|
265 err = CJesScheduler::Create(serverHandle); |
|
266 } |
|
267 |
|
268 server->Started(err, serverHandle); // don't touch server again - its gone. |
|
269 server = NULL; |
|
270 if (err==KErrNone) |
|
271 { |
|
272 CActiveScheduler::Start(); |
|
273 } |
|
274 delete CActiveScheduler::Current(); // will delete all objects |
|
275 delete cleanup; |
|
276 return 0; |
|
277 } |
|
278 |
|
279 #ifndef JAVA_STACKSIZE |
|
280 #define JAVA_STACKSIZE 0x2000 |
|
281 #endif |
|
282 |
|
283 void CJavaEventServer::ConstructL(const TDesC& aUserName, TThreadFunction aServerThread, TAny* aServerArg, |
|
284 TUint aStackSize, RAllocator* aHeap) |
|
285 // |
|
286 // Main construction of the event server |
|
287 // |
|
288 { |
|
289 User::LeaveIfError(iMutex.CreateLocal()); |
|
290 |
|
291 if (NULL == aServerThread) |
|
292 { |
|
293 // default thread function. |
|
294 aServerThread = &ServerThread; |
|
295 } |
|
296 |
|
297 TJesParam param; |
|
298 param.iArg = aServerArg; |
|
299 User::LeaveIfError(param.iThread.Duplicate(param.iThread,EOwnerProcess)); // make the thread handle process relative |
|
300 CleanupClosePushL(param.iThread); |
|
301 TRequestStatus s(KRequestPending); |
|
302 param.iStatus=&s; |
|
303 RThread js; |
|
304 if (aStackSize == 0) |
|
305 { |
|
306 aStackSize = JAVA_STACKSIZE; |
|
307 } |
|
308 |
|
309 TJesName name(aUserName,TJavaEventServer::Handle(this)); |
|
310 User::LeaveIfError(js.Create(name,aServerThread,aStackSize,aHeap,¶m,EOwnerProcess)); |
|
311 // js.SetPriority(EPriorityMore); |
|
312 js.Resume(); |
|
313 js.Close(); |
|
314 User::WaitForRequest(s); // wait for signal from server thread |
|
315 User::LeaveIfError(s.Int()); |
|
316 CleanupStack::PopAndDestroy(); // param.iThread |
|
317 User::LeaveIfError(iSession.Connect(param.iServerHandle)); |
|
318 } |
|
319 |
|
320 CJavaEventServer::CJavaEventServer() |
|
321 { |
|
322 } |
|
323 |
|
324 CJavaEventServer::~CJavaEventServer() |
|
325 { |
|
326 iSession.Close(); |
|
327 iMutex.Close(); |
|
328 } |
|
329 |
|
330 CJavaEventServer* CJavaEventServer::NewL(const TDesC& aUserName,TThreadFunction aServerThread, TAny* aServerArg, |
|
331 TUint aStackSize, RAllocator* aHeap) |
|
332 { |
|
333 CJavaEventServer* self=new(ELeave) CJavaEventServer; |
|
334 CleanupStack::PushL(self); |
|
335 self->ConstructL(aUserName, aServerThread, aServerArg, aStackSize, aHeap); |
|
336 CleanupStack::Pop(); |
|
337 return self; |
|
338 } |
|
339 |
|
340 // class CJavaEventBase |
|
341 |
|
342 void CJavaEventBase::Run(JNIEnv& aJni) |
|
343 // |
|
344 // Dispatch this event and destroy the event object |
|
345 // |
|
346 { |
|
347 CJavaEventSourceBase& source = Object(); |
|
348 |
|
349 // check if the event type is disposable before calling java callback |
|
350 // because if it's reusable it can be destroyed during servicing process |
|
351 TBool isDisposable = IsDisposable(); |
|
352 |
|
353 if (!source.IsDisposed() && !aJni.IsSameObject(source.Peer(),0)) |
|
354 { |
|
355 if (aJni.PushLocalFrame(16)==0) |
|
356 { |
|
357 Dispatch(aJni); |
|
358 if (aJni.ExceptionCheck()) |
|
359 { // Report any exceptions that were generated and clear them from the JNI environment |
|
360 aJni.ExceptionDescribe(); |
|
361 aJni.ExceptionClear(); |
|
362 } |
|
363 aJni.PopLocalFrame(0); |
|
364 } |
|
365 } |
|
366 if (isDisposable) |
|
367 { |
|
368 delete this; |
|
369 } |
|
370 // Close must be called last, because it may result in the destruction of this |
|
371 // event object if the event is a reusable event |
|
372 source.Close(aJni); |
|
373 } |
|
374 |
|
375 // class CJesSession |
|
376 |
|
377 inline TInt CJesSession::TExecute::operator()() const |
|
378 { |
|
379 return iFunc(iParam[0],iParam[1],iParam[2],iParam[3],iParam[4],iParam[5],iParam[6],iParam[7],iParam[8]); |
|
380 } |
|
381 |
|
382 TInt CJesSession::ExecuteTrap(const TExecute& aExecute) |
|
383 // |
|
384 // Execute the client function inside a trap harness |
|
385 // |
|
386 { |
|
387 TRAPD(r,aExecute()); |
|
388 return r; |
|
389 } |
|
390 |
|
391 |
|
392 void CJesSession::ServiceL(const RMessage2& m) |
|
393 // |
|
394 // Invoke the requested client function |
|
395 // |
|
396 { |
|
397 switch (m.Function()) |
|
398 { |
|
399 case EJessExecute: |
|
400 { |
|
401 const TExecute& e = *static_cast<const TExecute*>(m.Ptr0()); |
|
402 TInt result = e(); |
|
403 m.Complete(result != KRequestPending ? result : KErrNotSupported); |
|
404 } |
|
405 break; |
|
406 |
|
407 case EJessExecuteTrap: |
|
408 m.Complete(ExecuteTrap(*static_cast<const TExecute*>(m.Ptr0()))); |
|
409 break; |
|
410 |
|
411 case EJessShutdown: |
|
412 ((CJesServer*)Server())->Shutdown(); |
|
413 m.Complete(KErrNone); |
|
414 break; |
|
415 } |
|
416 } |
|
417 |
|
418 CJesShutdown::CJesShutdown(MJesShutdown* aShutdown) |
|
419 : CActive(CActive::EPriorityStandard) |
|
420 , iShutdown(aShutdown) |
|
421 { |
|
422 } |
|
423 |
|
424 void CJesShutdown::Start() |
|
425 { |
|
426 CActiveScheduler::Add(this); |
|
427 iStatus=KRequestPending; |
|
428 TRequestStatus* status = &iStatus; |
|
429 User::RequestComplete(status, KErrNone); |
|
430 SetActive(); |
|
431 } |
|
432 |
|
433 void CJesShutdown::RunL() |
|
434 { |
|
435 ASSERT(iShutdown); |
|
436 iShutdown->Shutdown(); |
|
437 iShutdown = NULL; |
|
438 } |
|
439 |
|
440 TInt CJesShutdown::RunError(TInt aError) |
|
441 { |
|
442 if (aError == KLeaveExit) |
|
443 { |
|
444 return aError; |
|
445 } |
|
446 return KErrNone; |
|
447 } |
|
448 |
|
449 void CJesShutdown::DoCancel() |
|
450 { |
|
451 // nop |
|
452 } |
|
453 |
|
454 // Helper method to trace output (int) to Java side, eg. System.out |
|
455 void CJavaEventServer::Trace(JNIEnv& aJni, TInt value) |
|
456 { |
|
457 jclass clazz = aJni.FindClass("com/symbian/lcdjava/lang/SystemExtensions"); |
|
458 jmethodID method = aJni.GetStaticMethodID(clazz, "trace" , "(I)V"); |
|
459 aJni.CallStaticVoidMethod(clazz, method, value); |
|
460 } |
|
461 |
|
462 // Notify Java thread of a new event |
|
463 void CJavaEventServer::NotifyJavaCall(TInt aEvent, TInt aPriority) |
|
464 { |
|
465 CEventQueue::NotifyServer(aEvent, aPriority); |
|
466 } |
|
467 |
|
468 |
|
469 void CJavaEventServer::Cleanup(RArray<TInt>& aServerHandles) |
|
470 { |
|
471 CEventQueue::Cleanup(); |
|
472 |
|
473 // Loop through event server instances and remove each |
|
474 for (TInt i = aServerHandles.Count() - 1; i >= 0; --i) |
|
475 { |
|
476 TInt handle = aServerHandles[i]; |
|
477 aServerHandles.Remove(i); |
|
478 delete JavaUnhand<CJavaEventServer>(handle); |
|
479 } |
|
480 } |
|
481 |