I have read many lessons and posts here about SO regarding the use of WakeLock and WifiLock, but still have not been able to solve the problem.
I am writing an application that, when you start it, is the only effect of creating and starting a service (foreground). This service starts two streams, which are the UDP broadcast listener (using java.io) and the TCP server (using java.nio). In the onCreate service, I acquire wakelock and wifilock, and I release them in onDestroy.
Everything works fine while the phone is awake, but when the display turns off, the UDP broadcast receiver stops receiving broadcast messages and will not receive any messages until I turn on the display again. In practice, the locks do not work at all, and there is no difference in putting them ... where am I mistaken? I’m sure that I’m doing something stupid, but I can’t find it myself.
Here is the code:
This action:
protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); onlyStartService = true; }@Override protected void onStart() { super.onStart(); Intent bIntent = new Intent(this, FatLinkService.class); getApplicationContext().startService(bIntent); getApplicationContext().bindService(bIntent, flConnection, BIND_AUTO_CREATE); } // service connection to bind idle service private ServiceConnection flConnection = new ServiceConnection() { public void onServiceConnected(ComponentName className, IBinder binder) { linkService.MyLinkBinder flBinder = (LinkService.MylinkBinder) binder; flServiceInstance = flBinder.getService(); if (onlyStartService) { condLog("Service bound and finishing activity..."); finish(); } } public void onServiceDisconnected(ComponentName className) { flServiceInstance = null; } }; @Override protected void onStop() { super.onStop(); if (fatFinish) { Intent bIntent = new Intent(this, FatLinkService.class); flServiceInstance.stopServices(); flServiceInstance.stopForeground(true); flServiceInstance.stopService(bIntent); condLog("Service stop and unbound"); flServiceInstance = null; } getApplicationContext().unbindService(flConnection); }
Here's how to do it:
public class LinkService extends Service { InetAddress iaIpAddr, iaNetMask, iaBroadcast; private final IBinder mBinder = new MyLinkBinder(); private linklistenBroadcast flBroadServer = null; private linkTCPServer flTCPServer = null; private linkUDPClient flBroadClient = null; List<String> tokens = new ArrayList<String>(); private PowerManager.WakeLock wakeLock; private WifiManager.WifiLock wifiLock; public class MylLinkBinder extends Binder { lLinkService getService() { return LinkService.this; } } @Override public IBinder onBind(Intent intent) { return mBinder; } @Override public void onCreate() { super.onCreate(); getLocks(); } @Override public int onStartCommand(Intent intent, int flags, int startId) { instantiateServices(); // notifies presence to other fat devices condLog("Service notifying fat presence..."); flBroadClient = new LinkUDPClient(); flBroadClient.startSending(LinkProtocolConstants.BRCMD_PRESENCE + String.valueOf(LinkProtocolConstants.tcpPort), iaBroadcast, LinkProtocolConstants.brPort); return START_STICKY; } public void getLocks() { // acquire a WakeLock to keep the CPU running condLog("Acquiring power lock"); WifiManager wm = (WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE); wifiLock = wm.createWifiLock(WifiManager.WIFI_MODE_FULL , "MyWifiLock"); wifiLock.acquire(); PowerManager pm = (PowerManager) getApplicationContext().getSystemService(Context.POWER_SERVICE); wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "MyWakeLock"); wakeLock.acquire(); } public void stopServices() { if (flTCPServer != null) flTCPServer.stopServer(); if (flBroadServer != null) flBroadServer.stopSelf(); } private void instantiateServices() { populateAddresses(); // just obtain iaIpAddr if (flTCPServer == null) { condLog("Instantiating TCP server"); flTCPServer = new LinkTCPServer(iaIpAddr, FatLinkProtocolConstants.tcpPort); flTCPServer.execute(); } if (flBroadServer == null) { condLog("Instantiating UDP broadcast server"); Intent notifyIntent = new Intent(this, LinkMain.class); // this is the main Activity class notifyIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP); notifyIntent.setAction("FROM_NOTIFICATION"); PendingIntent notifyPIntent = PendingIntent.getActivity(this, 0, notifyIntent, 0); Notification fixNotification = new Notification.Builder(getApplicationContext()) .setContentTitle("Link") .setSmallIcon(R.mipmap.imgLink) .setContentIntent(notifyPIntent) .build(); startForeground(1234, fixNotification); flBroadServer = new LinklistenBroadcast(); flBroadServer.start(); } } private final class LinklistenBroadcast extends Thread { private boolean bStopSelf = false; DatagramSocket socket; public void stopSelf() { bStopSelf = true; socket.close(); } @Override public void run() { condLog( "Listening broadcast thread started"); bStopSelf = false; try { //Keep a socket open to listen to all the UDP trafic that is destinated for this port socket = new DatagramSocket(null); socket.setReuseAddress(true); socket.setSoTimeout(LinkGeneric.BR_SOTIMEOUT_MILS); socket.setBroadcast(true); socket.bind(new InetSocketAddress(InetAddress.getByName("0.0.0.0"), FatLinkProtocolConstants.brPort)); while (true) { condLog("Ready to receive broadcast packets..."); //Receive a packet byte[] recvBuf = new byte[1500]; DatagramPacket packet = new DatagramPacket(recvBuf, recvBuf.length); try { socket.receive(packet); } catch (InterruptedIOException sException) { condLog(sockExcept.toString()); break; } catch (SocketException sockExcept) { condLog(sockExcept.toString()); } if (bStopSelf) { condLog("Broadcast server stopped..."); break; } int len = packet.getLength(); String datarecvd = new String(packet.getData()).trim(); //datarecvd = datarecvd.substring(0, len); //Packet received String message = new String(packet.getData()).trim(); condLog("<<< broadcast packet received from: " + packet.getAddress().getHostAddress() + " on port: " + packet.getPort() + ", message: " + message); if (packet.getAddress().equals(iaIpAddr)) { condLog("Ooops, it me! discarding packet..."); continue; } else condLog("<<< Packet received; data size: " + len + " bytes, data: " + datarecvd); //See if the packet holds the right command (message) // protocol decode // here do some tuff } catch (IOException ex) { condLog(ex.toString()); } if (socket.isBound()) { condLog( "Closing socket"); socket.close(); } condLog( "UDP server thread end."); flTCPServer = null; flBroadServer = null; } public boolean isThreadRunning() { return !bStopSelf; }; } // Utility functions public boolean checkBroadcastConnection (DatagramSocket socket, int timeOutcycles) { int tries = 0; while (!socket.isConnected()) { tries++; if (tries >= timeOutcycles) return false; } return true; } @Override public void onDestroy() { super.onDestroy(); if (wakeLock != null) { if (wakeLock.isHeld()) { wakeLock.release(); } } if (wifiLock != null) { if (wifiLock.isHeld()) { wifiLock.release(); } } }
}
And finally, here is the manifest:
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="xxxxxx.ink" > <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" /> <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" /> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.WAKE_LOCK" /> <uses-permission android:name="android.permission.WRITE_SETTINGS" /> <application android:allowBackup="true" android:icon="@mipmap/imgLinkmascotte" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name=".LinkMain" android:label="@string/app_name" android:theme="@android:style/Theme.Translucent.NoTitleBar.Fullscreen"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <service android:name=".LinkService" /> </application> </manifest>
I read this one and I have a doubt that the problem is the same, but actually it happens to me on the whole phone that I tried (Galaxy SIII, Galaxy Note 3 Neo, Galaxy SIII mini) with releases from 4.0 to 4.4.
I already tried the solution posted here , but something has changed (again ... this is a little frustrating).
I even tried setting the “Keep Wi-Fi on standby” setting to “Always” on all the phones I tried, but still nothing.
I studied the WakeFulIntentService class, which should work, since everyone says that it is, but I do not see the differences in my code.
I really hope someone can help me, I am really stuck with this from last week.
EDIT: after waqaslam's answer, I checked the device with the “Wi-Fi Optimization” option in the Wifi-Advaced settings and it really works as soon as I turned off this option. So now the problem: is it possible to turn off Wi-Fi optimization on devices that do not appear in the advanced menu? as I wrote below in my comment, this does not seem to apply to the release of Android, since I have two devices (both Samsung) with 4.4.2, and they do not show this option.
New EDIT: from waqaslam's edited answer, I tried to add multicastlock to my service, but again everything changed. It becomes annoying, it is unlikely that something is easy and understandable to do with the android.
Thanks a lot S.