001: /*
002: *
003: *
004: * Copyright 1990-2007 Sun Microsystems, Inc. All Rights Reserved.
005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License version
009: * 2 only, as published by the Free Software Foundation.
010: *
011: * This program is distributed in the hope that it will be useful, but
012: * WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * General Public License version 2 for more details (a copy is
015: * included at /legal/license.txt).
016: *
017: * You should have received a copy of the GNU General Public License
018: * version 2 along with this work; if not, write to the Free Software
019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA
021: *
022: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
023: * Clara, CA 95054 or visit www.sun.com if you need additional
024: * information or have any questions.
025: */
026:
027: package com.sun.midp.main;
028:
029: import com.sun.midp.events.*;
030:
031: import com.sun.midp.lcdui.ForegroundEventProducer;
032:
033: import com.sun.midp.midlet.*;
034:
035: import com.sun.midp.security.*;
036:
037: import com.sun.midp.log.Logging;
038: import com.sun.midp.log.LogChannels;
039: import com.sun.midp.configurator.Constants;
040: import com.sun.midp.suspend.SuspendSystemListener;
041: import com.sun.midp.suspend.SuspendSystem;
042:
043: import com.sun.cldc.isolate.Isolate;
044:
045: /**
046: * This is an implementation of the native application manager peer
047: * for the MVM mode of VM capable of running with
048: * more than 1 midlet concurrently. It notifies it peer of MIDlet state
049: * changes, but not this MIDlet.
050: */
051: public class NativeAppManagerPeer implements MIDletProxyListListener,
052: IsolateMonitorListener, EventListener, SuspendSystemListener {
053:
054: /** If true, the main of this class has already been called. */
055: static boolean alreadyCalled = false;
056:
057: /** return value from Main, so we know that Main exited normally */
058: static final int MAIN_EXIT = 2001;
059:
060: /** Singleton native app manager peer reference. */
061: private static NativeAppManagerPeer singleton;
062:
063: /**
064: * Inner class to request security token from SecurityInitializer.
065: * SecurityInitializer should be able to check this inner class name.
066: */
067: static private class SecurityTrusted implements
068: ImplicitlyTrustedClass {
069: }
070:
071: /**
072: * Called at the initial start of the VM.
073: * Initializes internal security and any other AMS classes related
074: * classes before starting the MIDlet.
075: *
076: * @param args not used
077: */
078: public static void main(String args[]) {
079:
080: // Since this is public method, guard against multiple calls
081:
082: if (alreadyCalled) {
083: throw new SecurityException();
084: }
085:
086: alreadyCalled = true;
087:
088: try {
089: try {
090: singleton = new NativeAppManagerPeer();
091: } catch (Throwable exception) {
092: notifySystemStartError();
093: throw exception;
094: }
095:
096: notifySystemStart();
097: singleton.processNativeAppManagerRequests();
098: } catch (Throwable exception) {
099: if (Logging.TRACE_ENABLED) {
100: Logging.trace(exception,
101: "Exception caught in NativeManagerPeer");
102: }
103: } finally {
104: exitInternal(MAIN_EXIT);
105: }
106: }
107:
108: /** Security token for using protected APIs. */
109: private SecurityToken internalSecurityToken;
110:
111: /** MIDlet proxy list reference. */
112: private MIDletProxyList midletProxyList;
113:
114: /** Event queue reference. */
115: private EventQueue eventQueue;
116:
117: /**
118: * Create and initialize a new native app manager peer MIDlet.
119: */
120: private NativeAppManagerPeer() {
121: /*
122: * WARNING: Don't add any calls before this !
123: *
124: * Register AMS Isolate ID in native global variable.
125: * Since native functions rely on this value to distinguish
126: * whether Java AMS is running, this MUST be called before any
127: * other native functions from this Isolate. I.E. This call
128: * must be the first thing this main class makes.
129: */
130: registerAmsIsolateId();
131:
132: internalSecurityToken = SecurityInitializer
133: .requestToken(new SecurityTrusted());
134: eventQueue = EventQueue.getEventQueue(internalSecurityToken);
135:
136: // current isolate & AMS isolate is the same object
137: int amsIsolateId = MIDletSuiteUtils.getAmsIsolateId();
138: int currentIsolateId = MIDletSuiteUtils.getIsolateId();
139:
140: // init AMS task resources needed for all tasks
141: MIDletSuiteUtils.initAmsResources();
142:
143: // create all needed event-related objects but not initialize ...
144: MIDletEventProducer midletEventProducer = new MIDletEventProducer(
145: eventQueue);
146:
147: MIDletControllerEventProducer midletControllerEventProducer = new MIDletControllerEventProducer(
148: eventQueue, amsIsolateId, currentIsolateId);
149:
150: ForegroundEventProducer foregroundEventProducer = new ForegroundEventProducer(
151: eventQueue);
152:
153: midletProxyList = new MIDletProxyList(eventQueue);
154:
155: // do all initialization for already created event-related objects ...
156: MIDletProxy.initClass(foregroundEventProducer,
157: midletEventProducer);
158: MIDletProxyList.initClass(midletProxyList);
159:
160: AmsUtil.initClass(midletProxyList,
161: midletControllerEventProducer);
162:
163: midletProxyList.addListener(this );
164: midletProxyList
165: .setDisplayController(new NativeDisplayControllerPeer(
166: midletProxyList));
167:
168: IsolateMonitor.addListener(this );
169:
170: SuspendSystem.getInstance(internalSecurityToken).addListener(
171: this );
172:
173: eventQueue.registerEventListener(
174: EventTypes.NATIVE_MIDLET_EXECUTE_REQUEST, this );
175: eventQueue.registerEventListener(
176: EventTypes.NATIVE_MIDLET_RESUME_REQUEST, this );
177: eventQueue.registerEventListener(
178: EventTypes.NATIVE_MIDLET_PAUSE_REQUEST, this );
179: eventQueue.registerEventListener(
180: EventTypes.NATIVE_MIDLET_DESTROY_REQUEST, this );
181: eventQueue.registerEventListener(
182: EventTypes.NATIVE_MIDLET_GETINFO_REQUEST, this );
183: eventQueue.registerEventListener(
184: EventTypes.NATIVE_SET_FOREGROUND_REQUEST, this );
185:
186: IndicatorManager.init(midletProxyList);
187:
188: NamsTestService.init(internalSecurityToken, eventQueue);
189: }
190:
191: /**
192: * Called in the main VM thread to keep the thread alive to until
193: * shutdown completes.
194: */
195: private void processNativeAppManagerRequests() {
196: midletProxyList.waitForShutdownToComplete();
197:
198: /*
199: * Shutdown the event queue gracefully to process any events
200: * that may be in the queue currently.
201: */
202: eventQueue.shutdown();
203: }
204:
205: // ==============================================================
206: // ------ Implementation of the MIDletProxyListListener interface
207:
208: /**
209: * Called when a MIDlet is added to the list.
210: *
211: * @param midlet The proxy of the MIDlet being added
212: */
213: public void midletAdded(MIDletProxy midlet) {
214: notifyMidletCreated(midlet.getExternalAppId());
215: }
216:
217: /**
218: * Called when the state of a MIDlet in the list is updated.
219: *
220: * @param midlet The proxy of the MIDlet that was updated
221: * @param fieldId code for which field of the proxy was updated
222: */
223: public void midletUpdated(MIDletProxy midlet, int fieldId) {
224: if (fieldId == MIDLET_STATE) {
225: if (midlet.getMidletState() == MIDletProxy.MIDLET_ACTIVE) {
226: notifyMidletActive(midlet.getExternalAppId());
227: return;
228: }
229:
230: if (midlet.getMidletState() == MIDletProxy.MIDLET_PAUSED) {
231: notifyMidletPaused(midlet.getExternalAppId());
232: return;
233: }
234: }
235: }
236:
237: /**
238: * Called when a MIDlet is removed from the list.
239: *
240: * @param midlet The proxy of the removed MIDlet
241: */
242: public void midletRemoved(MIDletProxy midlet) {
243: notifyMidletDestroyed(midlet.getExternalAppId());
244: }
245:
246: /**
247: * Called when error occurred while starting a MIDlet object.
248: *
249: * @param externalAppId ID assigned by the external application manager
250: * @param suiteId Suite ID of the MIDlet
251: * @param className Class name of the MIDlet
252: * @param errorCode start error code
253: * @param errorDetails start error details
254: */
255: public void midletStartError(int externalAppId, int suiteId,
256: String className, int errorCode, String errorDetails) {
257: notifyMidletStartError(externalAppId, errorCode);
258: }
259:
260: // ------ End implementation of the MIDletProxyListListener interface
261: // ==============================================================
262:
263: // ==============================================================
264: // ------ Implementation of the IsolateMonitorListener interface
265:
266: /**
267: * Called when a suite isolate is terminated.
268: *
269: * @param suiteId ID of the suite
270: */
271: public void suiteTerminated(int suiteId) {
272: notifySuiteTerminated(suiteId);
273: }
274:
275: // ------ End implementation of the IsolateMonitorListener interface
276: // ==============================================================
277:
278: // ==============================================================
279: // ------ Implementation of the EventListener interface
280:
281: /**
282: * Preprocess an event that is being posted to the event queue.
283: * This method will get called in the thread that posted the event.
284: *
285: * @param event event being posted
286: *
287: * @param waitingEvent previous event of this type waiting in the
288: * queue to be processed
289: *
290: * @return true to allow the post to continue, false to not post the
291: * event to the queue
292: */
293: public boolean preprocess(Event event, Event waitingEvent) {
294: return true;
295: }
296:
297: /**
298: * Process an event.
299: * This method will get called in the event queue processing thread.
300: *
301: * @param event event to process
302: */
303: public void process(Event event) {
304: String errorMsg = null;
305:
306: NativeEvent nativeEvent = (NativeEvent) event;
307: MIDletProxy midlet = midletProxyList
308: .findMIDletProxy(nativeEvent.intParam1);
309:
310: switch (nativeEvent.getType()) {
311:
312: case EventTypes.NATIVE_MIDLET_EXECUTE_REQUEST:
313: if (midlet == null) {
314: if (nativeEvent.intParam2 == MIDletSuite.UNUSED_SUITE_ID) {
315: notifyMidletStartError(nativeEvent.intParam1,
316: Constants.MIDLET_ID_NOT_GIVEN);
317: } else if (nativeEvent.stringParam1 == null) {
318: notifyMidletStartError(nativeEvent.intParam1,
319: Constants.MIDLET_CLASS_NOT_GIVEN);
320: } else {
321: MIDletSuiteUtils.executeWithArgs(
322: internalSecurityToken,
323: nativeEvent.intParam1,
324: nativeEvent.intParam2,
325: nativeEvent.stringParam1,
326: nativeEvent.stringParam2,
327: nativeEvent.stringParam3,
328: nativeEvent.stringParam4,
329: nativeEvent.stringParam5,
330: nativeEvent.intParam3,
331: nativeEvent.intParam4,
332: nativeEvent.intParam5,
333: nativeEvent.stringParam6);
334: }
335: } else {
336: errorMsg = "Only one instance of a MIDlet can be launched";
337: }
338: break;
339:
340: case EventTypes.NATIVE_MIDLET_RESUME_REQUEST:
341: if (midlet != null) {
342: midlet.activateMidlet();
343: } else {
344: errorMsg = "Invalid App Id";
345: }
346: break;
347:
348: case EventTypes.NATIVE_MIDLET_PAUSE_REQUEST:
349: if (midlet != null) {
350: midlet.pauseMidlet();
351: } else {
352: errorMsg = "Invalid App Id";
353: }
354: break;
355:
356: case EventTypes.NATIVE_MIDLET_DESTROY_REQUEST:
357: /*
358: * IMPL_NOTE: nativeEvent.intParam2 is a timeout value which
359: * should be passed to MIDletProxy.destroyMidlet().
360: *
361: */
362: if (midlet != null) {
363: midlet.destroyMidlet();
364: } else {
365: errorMsg = "Invalid App Id";
366: }
367: break;
368:
369: case EventTypes.NATIVE_MIDLET_GETINFO_REQUEST:
370: int isolateId = midlet.getIsolateId();
371: Isolate task = null;
372: Isolate[] allTasks = Isolate.getIsolates();
373:
374: for (int i = 0; i < allTasks.length; i++) {
375: if (allTasks[i].id() == isolateId) {
376: task = allTasks[i];
377: break;
378: }
379: }
380:
381: if (task != null) {
382: /* Structure to hold run time information about a midlet. */
383: RuntimeInfo runtimeInfo = new RuntimeInfo();
384:
385: runtimeInfo.memoryTotal = task.totalMemory();
386: runtimeInfo.memoryReserved = task.reservedMemory();
387: runtimeInfo.usedMemory = task.usedMemory();
388: runtimeInfo.priority = task.getPriority();
389: // there is no Isolate API now
390: runtimeInfo.profileName = null;
391:
392: saveRuntimeInfoInNative(runtimeInfo);
393: }
394:
395: notifyOperationCompleted(
396: EventTypes.NATIVE_MIDLET_GETINFO_REQUEST,
397: nativeEvent.intParam1, (task == null) ? 1 : 0);
398: break;
399:
400: case EventTypes.NATIVE_SET_FOREGROUND_REQUEST:
401: // Allow Nams to explicitly set nothing to be in the foreground
402: // with special AppId 0
403: if (midlet != null
404: || nativeEvent.intParam1 == Constants.MIDLET_APPID_NO_FOREGROUND) {
405: if (midletProxyList.getForegroundMIDlet() == midlet
406: && midlet != null) {
407: // send the notification even if the midlet already has
408: // the foreground
409: NativeDisplayControllerPeer
410: .notifyMidletHasForeground(midlet
411: .getExternalAppId());
412: } else {
413: midletProxyList.setForegroundMIDlet(midlet);
414: }
415: } else {
416: errorMsg = "Invalid App Id";
417: }
418: break;
419:
420: default:
421: errorMsg = "Unknown event type " + event.getType();
422: break;
423: }
424:
425: if (Logging.REPORT_LEVEL <= Logging.ERROR && errorMsg != null) {
426: Logging.report(Logging.ERROR, LogChannels.LC_AMS, errorMsg);
427: }
428: }
429:
430: // ------ End implementation of the EventListener interface
431: // ==============================================================
432:
433: // ==============================================================
434: // ------ Implementation of the SuspendSystemListener interface
435:
436: /**
437: * Called if MIDP system has been suspended.
438: */
439: public void midpSuspended() {
440: notifySystemSuspended();
441: }
442:
443: /**
444: * Called if MIDP system has been resumed.
445: */
446: public void midpResumed() {
447: notifySystemStart();
448: }
449:
450: // ------ End implementation of the Listener interface
451: // ==============================================================
452:
453: /**
454: * Saves runtime information from the given structure
455: * into the native buffer.
456: *
457: * @param runtimeInfo structure holding the information to save
458: */
459: private static native void saveRuntimeInfoInNative(
460: RuntimeInfo runtimeInfo);
461:
462: /**
463: * Notify the native application manager that the system has completed
464: * the requested operation and the result (if any) is available.
465: *
466: * @param operation code of the operation that has completed
467: * @param externalAppId ID assigned by the external application manager
468: * @param retCode completion code (0 if OK)
469: */
470: private static native void notifyOperationCompleted(int operation,
471: int externalAppId, int retCode);
472:
473: /**
474: * Notify the native application manager that the system had an error
475: * starting.
476: */
477: private static native void notifySystemStartError();
478:
479: /**
480: * Notify the native application manager of the system start up.
481: */
482: private static native void notifySystemStart();
483:
484: /**
485: * Notifies native application manager on MIDP suspension.
486: */
487: private static native void notifySystemSuspended();
488:
489: /**
490: * Notify the native application manager of the MIDlet creation.
491: *
492: * @param externalAppId ID assigned by the external application manager
493: * @param error error code
494: */
495: private static native void notifyMidletStartError(
496: int externalAppId, int error);
497:
498: /**
499: * Notify the native application manager of the MIDlet creation.
500: *
501: * @param externalAppId ID assigned by the external application manager
502: */
503: private static native void notifyMidletCreated(int externalAppId);
504:
505: /**
506: * Notify the native application manager that the MIDlet is active.
507: *
508: * @param externalAppId ID assigned by the external application manager
509: */
510: private static native void notifyMidletActive(int externalAppId);
511:
512: /**
513: * Notify the native application manager that the MIDlet is paused.
514: *
515: * @param externalAppId ID assigned by the external application manager
516: */
517: private static native void notifyMidletPaused(int externalAppId);
518:
519: /**
520: * Notify the native application manager that the MIDlet is destroyed.
521: *
522: * @param externalAppId ID assigned by the external application manager
523: */
524: private static native void notifyMidletDestroyed(int externalAppId);
525:
526: /**
527: * Notify the native application manager that the suite is terminated.
528: *
529: * @param suiteId ID of the MIDlet suite
530: */
531: private static native void notifySuiteTerminated(int suiteId);
532:
533: /**
534: * Register the Isolate ID of the AMS Isolate by making a native
535: * method call that will call JVM_CurrentIsolateId and set
536: * it in the proper native variable.
537: */
538: private static native void registerAmsIsolateId();
539:
540: /**
541: * Exit the VM with an error code. Our private version of Runtime.exit.
542: * <p>
543: * This is needed because the MIDP version of Runtime.exit cannot tell
544: * if it is being called from a MIDlet or not, so it always throws an
545: * exception.
546: * <p>
547: *
548: * @param status Status code to return.
549: */
550: private static native void exitInternal(int status);
551: }
|