×

Discussion Board

Results 1 to 9 of 9
  1. #1
    Registered User
    Join Date
    Nov 2007
    Posts
    16

    Exclamation JSR-179 : serious bug in getLocation implementation

    In developing a location-aware application using JSR-179 on the Nokia 6110 I noticed some nasty problems with getLocation() leading to device lock-ups.

    My app calls getLocation regularly, but infrequently (explanation below). Here are some of the problems I found:

    (A) getLocation sometimes (apparently randomly) blocks forever regardless of the timeout value; the MIDlet can be terminated but does not close cleanly. In this state the CPU appears to be under high load - response in the UI is sluggish. Any app that attempts to access the GPS (eg. Navigator, or GPS Data) will hang. The phone must be power cycled to resume normal operations.

    (B) In long-running apps, getLocation eventually stops working if no fix is available. It fails to wait for the timeout period but returns immediately. Other apps that attempt to connect to the GPS server return "No Connection". Eventually, other apps cannot be started with the phone giving "Memory full. Close some applications and try again". To me this suggests a resource leak in the handling of location exceptions.

    This normally happens when the phone has had a GPS fix and lost it again.

    Some background: My app needs to sample position infrequently, but must run continuously. JSR-179 offers two ways to access location information. You can do blocking (synchronous) calls to LocationProvider.getLocation which wait until a location is known or a timeout period expires. Alternatively, you can use LocationProvider.setLocationListener to register for a notification (asyncrhonous) when location information is available.

    Recently nicholso reported a problem with the asynchronous API: when you remove the location listener and reset the provider, the GPS does not stop sampling if it already has a position fix. This happens on my 6110 - instead of entering a low-power mode it continues to consume about 120mA, giving a battery life of less than 8 hours. I don't want my users to have to recharge the phone more than once a day. I need at least 16 to 20 hours battery life, so I tried using a thread to periodically call getLocation, allowing the GPS to power down between samples. Unfortunately, getLocation is quite buggy and eventually the entire GPS system hangs along with the MIDlet.

    I've included some source code to reproduce these problems. I have two handsets which behave identically: one has the original firmware (V03.51, RM-122 Nokia 6110 24.02), and one was upgraded to the latest version (V04.22, RM-122 Nokia 6110 24.01).

    The MIDlet has two parameters: wait and timeout. In "synchronous" mode it calls getLocation(timeout), waiting for <wait> seconds between samples. In "asyncrhonous" mode it uses setLocationListener with <wait+timeout> as the interval.

    To reproduce the problem:
    1. Start the MIDlet and set the timing parameters. The shorter the times, the less you have to wait. The app makes an initial reading (to get rid of the annoying permission request) which may fail.
    2. Select "Start Sync" to begin sampling using getLocation.
    3. Get a GPS fix, then lose it. For example: walk outside until you get a location, then back inside again until it is lost.
    4. Wait. If you have the right conditions the app will eventually hang - the display will stop updating. The phone will respond sluggishly and GPS apps will lock up. Alternatively, you may stop seeing the "getLocation" message because it fails to wait for the timeout period to expire. Try launching "GPS Data" and you will get either "No Connection" or "Memory Full".

    With timeout=1 and wait=1 I find it normally takes 10 to 15 minutes for the problem to occur, though it may depend on location.

    Based on my experience it seems impossible to implement a long-running GPS app using Nokia's JSR-179 due to a combination of bugs across the entire API. Has anyone managed to get a GPS MIDlet to run for more than a few hours on a single charge?

    Can anyone confirm this behaviour on other devices?

    Cheers,
    Stewart

    Code:
    import javax.microedition.lcdui.*;
    import javax.microedition.midlet.*;
    import javax.microedition.location.*;
    import java.util.Date;
    import java.io.PrintStream;
    
    public class TestMIDlet extends MIDlet implements CommandListener,
    LocationListener {
    	private Command exitAppCommand = new Command("Exit", Command.EXIT, 1);
    	private Command startSyncCommand = new Command("Start Sync", Command.SCREEN, 1);
    	private Command startAsyncCommand = new Command("Start Async", Command.SCREEN, 1);
    	private Command stopCommand = new Command("Stop", Command.SCREEN, 1);
    	private Command resetCommand = new Command("Reset GPS", Command.SCREEN, 1);
    	private Command exitOptionsCommand = new Command("Exit Options", Command.EXIT, 1);
    	private Command optionsCommand = new Command("Options", Command.SCREEN, 1);
    
    	private Form mainForm;
    	private Form optionsForm;
    	private TextField optTimeout;
    	private TextField optWait;
    	int timeout = 1;
    	int wait=1;
    	long startTime;
    	long fixTime;
    
    	private LocationProvider provider;
    
    	private int gpsState = 0;
    
    	TextField AppendNumericField(String name) {
    		TextField f = new TextField(name, "", 6, TextField.NUMERIC);
    		f.setLayout(Item.LAYOUT_SHRINK + Item.LAYOUT_RIGHT);
    		optionsForm.append(f);
    		return f;
    	}
    
    	void createOptionsForm() {
    		optionsForm = new Form("Options");
    		optTimeout = AppendNumericField("Timeout");
    		optWait = AppendNumericField("Wait");
    		optionsForm.addCommand(exitOptionsCommand);
    		optionsForm.setCommandListener(this);
    	}
    
    	void createMainForm() {
    		mainForm = new Form("Test GPS");
    		mainForm.addCommand(startSyncCommand);
    		mainForm.addCommand(startAsyncCommand);
    		mainForm.addCommand(stopCommand);
    		mainForm.addCommand(resetCommand);
    		mainForm.addCommand(optionsCommand);
    		mainForm.addCommand(exitAppCommand);
            mainForm.setCommandListener(this);
    	}
    
    	int ReadInteger(TextField t) throws Exception {
    		return Integer.parseInt(t.getString());
    	}
    
    	boolean readOptions() {
    		try {
    			int timeout1 = ReadInteger(optTimeout);
    			int wait1 = ReadInteger(optWait);
    			if (timeout1<=0) 
    				throw new Exception("Timeout must be greater than 0");
    			if (wait1<0)
    				throw new Exception("Wait must not be negative");
    			timeout = timeout1;
    			wait = wait1;
    			return true;
    		} catch (Exception e) {
    			Display.getDisplay(this).setCurrent(new Alert("Error", "Exception " + e, null, AlertType.ERROR));
    			return false;
    		}
    	}
    
    	void writeOptions() {
    		optWait.setString(Integer.toString(wait));
    		optTimeout.setString(Integer.toString(timeout));
    	}
    
    	void StartGPS() {
    		startTime = System.currentTimeMillis();
    		try {
    			if (provider == null) {
    				provider = LocationProvider.getInstance(null);
    				mainForm.append("Started GPS\n");
    				provider.getLocation(1);
    			}
    		} catch (Exception e) {
    			mainForm.append("StartGPS: " + e + "\n");
    		}
    	}
    
    	void showTime() {
    		long time = System.currentTimeMillis();
    		mainForm.deleteAll();
    		mainForm.append(new Date(time)+"\n");
    		mainForm.append("running: " + ((time-startTime)/1000) + "s\n");
    		mainForm.append("last fix: " + ((fixTime == 0) ? "none\n" : ((time-fixTime)/1000) + "s\n"));
    	}
    
    	void handleLocation(Location loc) {
    		if (loc.isValid()) {
    			fixTime = System.currentTimeMillis();
    			QualifiedCoordinates coord = loc.getQualifiedCoordinates();
    			mainForm.append("lat: " + coord.getLatitude() + "\n");
    			mainForm.append("lon: " + coord.getLongitude() + "\n");
    		} else {
    			mainForm.append("Invalid location\n");
    		}
    	}
    
    	public void locationUpdated(LocationProvider p, final Location loc) {
    		new Thread() {
    			public void run() { 
    				showTime();
    				handleLocation(loc); 
    			} 
    		} .start();
    	}
    
    	public void providerStateChanged(LocationProvider p, int state) {}
    
    	class Timer extends Thread {
    		void waitForDeadline(int period) {
    			period *= 1000; 
    			mainForm.append("sleep("+period+")\n");
    			try {
    				Thread.sleep(period);   
    			} catch (InterruptedException e) {
    			}
    		}
    
    		void getLocation(int timeout) {
    			try {
    				mainForm.append("getLocation("+timeout+")...\n");
    				Location loc = provider.getLocation(timeout);
    
    				showTime();
    				handleLocation(loc);
    			} catch (Exception e) {
    				showTime();
    				mainForm.append("Exception " + e + "\n");
    				return;
    			}
    		}
    
    		public void run() {
    			mainForm.append("Timer started\n");
    			while (true) {
    				switch (gpsState) {
    				case 0:	// idle
    					try {
    						Thread.sleep(1000);
    					} catch (InterruptedException e) {}
    					break;
    				case 1: // sampling
    					waitForDeadline(wait);
    					getLocation(timeout);
    					break;
    				}
    			}
    		}
    	};
    
    
    	Timer timer;
    
    	public TestMIDlet() {
    		createMainForm();
    		createOptionsForm();
    	}
    
    	void stop() {
    		if (provider != null)
    			provider.setLocationListener(null, -1, -1, -1);
    		gpsState = 0;
    	}
    
    	public void commandAction(Command c, Displayable s) {
    		if (c == exitAppCommand) {
    			destroyApp(true);
    			notifyDestroyed();
    		} else if (c==startSyncCommand) {
    			stop();
    			gpsState = 1;
    		} else if (c==startAsyncCommand) {
    			stop();
    			if (provider != null)
    				provider.setLocationListener(this, timeout + wait, timeout, -1);
    		} else if (c==stopCommand) {
    			stop();
    		} else if (c==optionsCommand) {
    			writeOptions();
    			Display.getDisplay(this).setCurrent(optionsForm);
    		} else if (c==resetCommand) {
    			if (provider != null) {
    				mainForm.append("Reset GPS\n");
    				provider.reset();
    			}
    		} else if (c==exitOptionsCommand) {
    			if (readOptions())
    				Display.getDisplay(this).setCurrent(mainForm);
    		}
    	}
    
    	public void destroyApp(boolean unconditional) { }
    
    	public void pauseApp() { }
    
    	public void startApp() {	
    		Display.getDisplay(this).setCurrent(mainForm);
    		if (timer == null) {
    			timer = new Timer(); timer.start();
    		}
    		StartGPS();
    	}
    }
    Last edited by sgreenhill; 2008-02-18 at 04:20.

  2. #2
    Regular Contributor
    Join Date
    May 2008
    Location
    Copenhagen, Denmark
    Posts
    84

    Re: JSR-179 : serious bug in getLocation implementation

    Hi Stewart

    You have any updates on this? Workarounds or ?

    /Torben

  3. #3
    Nokia Developer Expert
    Join Date
    Aug 2007
    Posts
    1,595

    Re: JSR-179 : serious bug in getLocation implementation

    Hello Torben,

    not very comforting, but here's one solution defined in this Forum Nokia Wiki Known Issue:

    http://wiki.forum.nokia.com/index.ph...d_battery_life

    Regards,
    r2j7
    [URL="http://library.forum.nokia.com/java"][B] >>> Java Developer's Library <<<[/B][/URL]
    [URL="https://www.developer.nokia.com/Resources/Support/Technical_support.xhtml"] [B]>>> Technical Support for Java ME development <<<[/B][/URL]
    [URL="https://publish.ovi.com/info/"][B]>>> Nokia Publish: reach millions of Nokia users worldwide through Nokia Store <<<[/B][/URL]

  4. #4
    Registered User
    Join Date
    Nov 2007
    Posts
    16

    Re: JSR-179 : serious bug in getLocation implementation

    That's not really a fix, but at least there is some official acknowledgement of the problem.

    As far as I know there is no workaround.

  5. #5
    Registered User
    Join Date
    Dec 2008
    Posts
    5

    Re: JSR-179 : serious bug in getLocation implementation

    Hi Stewart,

    i have the same problem with Nokia N85 and my long run apps that periodically call getLocation...

    getLocation fails approximately after 30min (err: Location request timed out) and the entire GPS system hangs.

    Recently I have reported the problem on the forum...

    have you found any Workarounds?

    Eritreo.

  6. #6
    Registered User
    Join Date
    Nov 2007
    Posts
    16

    Re: JSR-179 : serious bug in getLocation implementation

    Hi Eritreo,

    Sorry, but I'm not aware of any workarounds...

    I'm presuming that you've updated to the latest firmware. If the problem still exists, then the bug has not been fixed by Nokia.

    This is one of several bugs I've found in Nokia's Java stuff. Next time I'm looking closer at other alternatives (eg. Python-S60).

    Cheers,
    Stewart

  7. #7
    Registered User
    Join Date
    Dec 2008
    Posts
    5

    Re: JSR-179 : serious bug in getLocation implementation

    Hi Stewart,
    i have found a workaround that work with nokia N85 (with latest firmware).

    I use LocationProvider.setLocationListener to register for a notification and i do not getLocation calls, ever.
    If i make calls to getLocation, only two calls, the gps hangs.

    i test this solution with EnergyProfiler and the battery level normalized after exiting the MIDlet.

    Eritreo.

  8. #8
    Registered User
    Join Date
    Nov 2007
    Posts
    16

    Re: JSR-179 : serious bug in getLocation implementation

    OK, it sounds like you might be in luck.

    Be sure to read this thread regarding problems with the asynchronous API. In some situations, the GPS does not power down when you stop sampling. This can be a problem in long-running applications. Providing your application exits when its finished using the GPS you should be safe.

    Cheers,
    Stewart

  9. #9
    Registered User
    Join Date
    Aug 2008
    Posts
    6

    Re: JSR-179 : serious bug in getLocation implementation

    Yes I am also facing the same problems on (E71, N79, N95) devices.
    My application requesting GPS fix in every 3sec.

    I have faced all the problems listed

    1) After some time getting Location Exception "Location request timed out" & Location Provider state as Available.
    2) Application Hangs.
    3) Device Hangs if wants to resume needs to remove the battery.
    4) Native GPS app hangs or shows No Connection
    5) If application restarted within 1sec GPS fix recived.



    But found No issue while using E51 (Bluetooth GPS receiver device). The same app running fine............
    Last edited by abhisardeshmukh; 2010-08-03 at 15:14.

Similar Threads

  1. Replies: 7
    Last Post: 2008-02-08, 12:02
  2. JSR 179 problem
    By chesschi in forum Mobile Java General
    Replies: 1
    Last Post: 2007-09-13, 00:55
  3. E61, CDC & JSR 179
    By jdesjean in forum Mobile Java Tools & SDKs
    Replies: 2
    Last Post: 2007-06-27, 13:41
  4. JSR 179 Mobile registration info (newbie)
    By WonderP in forum Mobile Java General
    Replies: 1
    Last Post: 2007-02-28, 00:41
  5. JSR 179 Implementation
    By gruntzd in forum Mobile Java General
    Replies: 1
    Last Post: 2007-02-26, 07:31

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
×