Paho MQTT AlarmPingSender wakelock stucked - android

I am using Paho Android Service for my project (app name is Sealer). (link)
I've tested it about 22 hours and the result has brought me a strange result.
It seems that my app keeps awake the CPU a very long time (~10,5 h).
I've searched in the source code by wakelock tag and found that the wakelock tag belongs to the AlarmPingSender class. Has anybody met this problem ever ?
I didn't modify the Android Service source code, it's the original.
I've attached some screenshots (Hangouts and Viber just for comparison).
Screenshots
EDIT 1.
There is a code snippet from my source code:
mqttOptions = new MqttConnectOptions();
mqttOptions.setCleanSession(false);
// defaultKeepAlive is 240
mqttOptions.setKeepAliveInterval(Constants.defaultKeepAlive);
EDIT 2
I think this is the relevant code from Android Service source code:
/*
* This class sends PingReq packet to MQTT broker
*/
class AlarmReceiver extends BroadcastReceiver {
private WakeLock wakelock;
private String wakeLockTag = MqttServiceConstants.PING_WAKELOCK
+ that.comms.getClient().getClientId();
#Override
public void onReceive(Context context, Intent intent) {
// According to the docs, "Alarm Manager holds a CPU wake lock as
// long as the alarm receiver's onReceive() method is executing.
// This guarantees that the phone will not sleep until you have
// finished handling the broadcast.", but this class still get
// a wake lock to wait for ping finished.
int count = intent.getIntExtra(Intent.EXTRA_ALARM_COUNT, -1);
Log.d(TAG, "Ping " + count + " times.");
Log.d(TAG, "Check time :" + System.currentTimeMillis());
IMqttToken token = comms.checkForActivity();
// No ping has been sent.
if (token == null) {
return;
}
// Assign new callback to token to execute code after PingResq
// arrives. Get another wakelock even receiver already has one,
// release it until ping response returns.
if (wakelock == null) {
PowerManager pm = (PowerManager) service
.getSystemService(Service.POWER_SERVICE);
wakelock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
wakeLockTag);
}
wakelock.acquire();
token.setActionCallback(new IMqttActionListener() {
#Override
public void onSuccess(IMqttToken asyncActionToken) {
Log.d(TAG, "Success. Release lock(" + wakeLockTag + "):"
+ System.currentTimeMillis());
//Release wakelock when it is done.
if(wakelock != null && wakelock.isHeld()){
wakelock.release();
}
}
#Override
public void onFailure(IMqttToken asyncActionToken,
Throwable exception) {
Log.d(TAG, "Failure. Release lock(" + wakeLockTag + "):"
+ System.currentTimeMillis());
//Release wakelock when it is done.
if(wakelock != null && wakelock.isHeld()){
wakelock.release();
}
}
});
}
}
It seems (at least according to the screenshots) that the wakelock somehow is 'stucked', doesn't released.

I have the same problem and created a bug report. Please have a look for further help: https://bugs.eclipse.org/bugs/show_bug.cgi?id=480134

The ping sender will need to wake up to send a ping at what ever keep alive period is configured. The app needs to wake to send the packet that keeps the connection alive. I've not played with the Paho Android service but you should be able to change this by adding the relevant values to the MQTTConnectOptions object passed to the MQTTAndoridClient.connect() method.
EDIT:
e.g.
MQTTConnectOptions opts = new MQTTConnectOptions();
opts.setConnectionTimeout(240000);
client.connect(opts);

Related

Android Web socket Service is not maintain web connection when mobile screen off

I am using node.js web server by heroku and android client for web socket.io communication
I want to receive server message whenever it send to client Android, even the Android screen off
so I am basically make Service , socket.on listener , thread & handler on Android.
also did apply partial_wake_lock, foreground service, send Notification, ping-pong per every 5 seconds ...
my system is running well when Android's screen is on.
but around 30 seconds after Android screen off, web connection is going to disconnect
could you give me some example about long-run web socket Service source code or some solution about my code?
thank you for read.
mainActivity
PowerManager powerManager = (PowerManager) getSystemService(POWER_SERVICE);
PowerManager.WakeLock wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK |
PowerManager.ACQUIRE_CAUSES_WAKEUP |
PowerManager.ON_AFTER_RELEASE, "My:Tag");
wakeLock.acquire();
//apply wake_lock etc
(...)
Intent serviceIntent = new Intent(getApplicationContext(),CommunicationService.class);
startService(serviceIntent); //init service
communication Service (extends Service)
#Override
public int onStartCommand(Intent intent, int flags, int startId){
//start foreground-service
Intent notificationIntent = new Intent(this, MainActivity.class);
PendingIntent pendingIntent =
PendingIntent.getActivity(this, 0, notificationIntent, 0);
Log.d("gd","entering");
notification =
new Notification.Builder(this, CHANNEL_ID)
.setContentTitle("KD SERVICE TEST")
.setContentText("now koda testing" )
.setSmallIcon(R.drawable.ic_android_ex)
.setContentIntent(pendingIntent)
.build();
startForeground(1, notification);
if(webThread == null) {
Log.d("gd","webthread begin");
webThread = new WebThread(url, role, this.handler);
webThread.start();
}
return START_NOT_STICKY; //I tried STICKY, but nothing
class webThread extend Thread : constructor and run
in the webThread.run, the thread is always send 'ping' to server every 5second
and when server get 'ping' always answer 'pong'
in my intention, when there is no 'pong', it means correspond = false, try to socket.connect() again.
and this handler is come from communicationService.
public WebThread(String get_url, int input_role, android.os.Handler handler){
try {
socket = IO.socket(get_url);
Log.d("gd","socket status: 0 " + socket.connected());
socket.connect();
socket.emit("join",role,"01");
} catch (URISyntaxException e) {
Log.d("gd", "web server enter failed");
e.printStackTrace();
}
web_listener_init();
this.handler = handler;
Log.d("gd","web thread created");
}
#Override
public void run(){
while(true){
if(isInterrupted())
return;
//when connection status is fine, correspond == true.
if(correspond ==false) {
socket.connect();
socket.emit("join", role, "01");
}
Message msg = Message.obtain();
msg.what = STATE_HEARTBEAT;
handler.sendMessage(msg);
correspond = false;
try {
Thread.sleep(5000);
}
catch (InterruptedException e){
e.printStackTrace();
}
}
}
this is handler in communication service class.
Handler handler = new Handler(new Handler.Callback() {
#Override
public boolean handleMessage(Message msg) {
case STATE_HEARTBEAT:
webThread.getSocket().emit("send_ping");
//sendNotification("ping");
break;
case STATE_WEB_MESSAGE_RECEIVED:
String webMessage = msg.obj.toString();
Log.d("gd", "handler received from web: " + webMessage);
if(webMessage.equals("pong")){
webThread.isCorrespond(); // make webThread 's 'correspond' = true
}
});
I am using nkzawa Socket.io library. It will be very appreciate for give some advice.
I solved my problem. sudden disconnection is not from server / service / ping-pong.
is from android itself.
If don't apply wake_lock(paritial_wake_lock) on SERVICE class,
service do not maintain even its service is foreground, or notify regularly
I did put wake lock only in mainActivity, which is running before the service.
so apply wake_lock on the service and put manifest !

Android Wear Watch Face Vibrate With Screen Off

I have an Android Wear watch face that I'm trying to have vibrate the watch on the hour. It is working except in cases where the watch screen is off. According to the log statements, the handler method is called every minute and the chime method is called on the hour. If I'm debugging over bluetooth with the Moto 360, it works even with the screen off. If I install a release apk, it only vibrates if the screen is on. If the screen is off at the top of the hour, it wont vibrate until the screen comes back on. I have tried acquiring a wake lock before the vibrate with no luck. I'm thinking it may work if I acquire a wake lock in the onCreate and release it in the onDestroy but I would rather not do that to preserve battery. Another interesting tidbit is that I have another function that vibrates when certain data changes in the wearable data api and that is working with the screen off. Maybe the WearableListenerService wakes the watch up long enough for the vibrate to occur. Is there something wrong with my logic or is this a limitation of certain Android Wear devices?
Time change handler:
final Handler mUpdateTimeHandler = new Handler() {
#Override
public void handleMessage(Message message) {
switch (message.what) {
case MSG_UPDATE_TIME:
MyLog.d("Time Tick Message Handler");
doTimeTickStuff();
long timeMs = System.currentTimeMillis();
long delayMs = mInteractiveUpdateRateMs - (timeMs % mInteractiveUpdateRateMs);
mUpdateTimeHandler.sendEmptyMessageDelayed(MSG_UPDATE_TIME, delayMs);
break;
}
}
};
doTimeTickStuff()
private void doTimeTickStuff()
{
MyLog.d("timetickstuff");
try {
mCalendar = Calendar.getInstance();
int currMin = mCalendar.get(Calendar.MINUTE);
if (currMin == 0) {
hourlyChime();
}
}
catch(Exception ex)
{
MyLog.e(ex, "Error occurred in time tick handler");
}
if (mIsVisible) {
invalidate();
}
}
hourlyChime()
private void hourlyChime(){
Vibrator v = (Vibrator) getBaseContext().getSystemService(VIBRATOR_SERVICE);
if (v.hasVibrator()) {
MyLog.d("vibrating");
v.vibrate(1000);
}
else {
MyLog.d("No vibrator");
}
}
Update
The solution that worked was to create an AlarmManager and register it with a broadcast receiver in the watch face onCreate then unregister the receiver in onDestroy
onCreate()
#Override
public void onCreate(SurfaceHolder holder) {
super.onCreate(holder);
mChimeAlarmManager =
(AlarmManager) getSystemService(Context.ALARM_SERVICE);
Intent ambientStateIntent = new Intent("packagename.HOURLY_CHIME");
mChimePendingIntent = PendingIntent.getBroadcast(getApplicationContext(),
1234, ambientStateIntent, PendingIntent.FLAG_UPDATE_CURRENT);
WeatherTime.this.registerReceiver(chimeReceiver,
new IntentFilter("packagename.HOURLY_CHIME"));
long alarmMs = getMsTillNextHour() + System.currentTimeMillis();
mChimeAlarmManager.setExact(
AlarmManager.RTC_WAKEUP,
alarmMs,
mChimePendingIntent);
}
Broadcast Receiver
private BroadcastReceiver chimeReceiver = new BroadcastReceiver()
{
#Override
public void onReceive(Context context, Intent intent) {
hourlyChime();
mChimeAlarmManager.setExact(
AlarmManager.RTC_WAKEUP,
getMsTillNextHour() + System.currentTimeMillis(),
mChimePendingIntent);
}
};
onDestroy()
#Override
public void onDestroy() {
mChimeAlarmManager.cancel(mChimePendingIntent);
super.onDestroy();
}
When the watch goes into ambient mode, it goes into a deep sleep. As a result, code written with Handler will not run. As a result, you should use AlarmManager. For details on how to implement this, you should refer to the "Update more frequently" section on this page about the always-on functionality of Android Wear.
With regards to Bluetooth debug mode, I suspect that it works because the watch never goes into deep sleep. The same happens when I develop apps while the watch is docked.
Lastly, as for the wake up frequency, I think your functionality is fine as it only fires once an hour. For others reading this, please refrain from waking the watch up more than once a minute as this will severely impact battery life. Always test your watch face for battery life before uploading to the Play Store.
in my project i use Alarm manager with MyIntentService extends IntentService.
To wake up (on screen) device in onHandleIntent
use following:
if (intent.getAction() != null) {
tmp = intent.getAction();
PowerManager powerManager = (PowerManager) getSystemService(POWER_SERVICE);
wakeLock = powerManager.newWakeLock((PowerManager.SCREEN_BRIGHT_WAKE_LOCK | PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP), TAG);
wakeLock.setReferenceCounted(true);
if(!wakeLock.isHeld()) {
wakeLock.acquire();
}
}

Android Wear app that crashes when I release wakeLock

I have an extremely simple Android Wear app that basically is just one button on the mobile device that I want to use to turn the display of my Android Wear device on and off. I have the application sending messages to the Android Wear device to tell it to acquire or release a wakeLock depending on the screen state. The wakeLock.acquire() works perfectly fine but when I send the message to release the wakeLock the application misbehaves. Acquiring the wakeLock seems to always work but releasing it will cause one of the follwoing: it will either crash and say "Unfortunately your app has stopped working", or it won't do anything (as if it thinks I'm not holding the wakeLock so it doesn't even enter the if-statment that contains the release call) or it will see that it is held but my call to wakeLock.release() doesn't seem to actually release the lock (screen never dims). Any ideas?
Mobile Device Code:
// sendToast is the onClickListener function for my toggleButton
private void sendToast() {
if(isChecked(findViewById(R.id.toggleButton)))
message = ON_MESSAGE;
else
message = OFF_MESSAGE;
if (nodeId != null) {
new Thread(new Runnable() {
#Override
public void run() {
client.blockingConnect(CONNECTION_TIME_OUT_MS, TimeUnit.MILLISECONDS);
Wearable.MessageApi.sendMessage(client, nodeId, message, null);
client.disconnect();
}
}).start();
}
}
private boolean isChecked(View view) {
if (((ToggleButton) view).isChecked())
return true;
else
return false;
}
Wear Device Code:
public class ListenerService extends WearableListenerService {
private PowerManager powerManager;
private PowerManager.WakeLock wakeLock;
private static final String ON_MESSAGE = "On!";
private static final String OFF_MESSAGE = "Off!";
boolean first = true;
private void setupWakeLock() {
powerManager = (PowerManager) getSystemService(POWER_SERVICE);
wakeLock = powerManager.newWakeLock(PowerManager.FULL_WAKE_LOCK |
PowerManager.ACQUIRE_CAUSES_WAKEUP, "wakeLock"); // SCREEN_BRIGHT_WAKE_LOCK
}
#Override
public void onMessageReceived(MessageEvent messageEvent) {
if (first) {
setupWakeLock();
first = false;
}
Toast.makeText(this, wakeLock.toString(), Toast.LENGTH_LONG).show();
if (messageEvent.getPath().equals(ON_MESSAGE)) {
if (!wakeLock.isHeld()) {
wakeLock.acquire();
Toast.makeText(this, ON_MESSAGE, Toast.LENGTH_LONG).show();
}
} else if (messageEvent.getPath().equals(OFF_MESSAGE)) {
if (wakeLock.isHeld()) {
wakeLock.release();
Toast.makeText(this, OFF_MESSAGE, Toast.LENGTH_LONG).show();
}
}
}
private void showToast(String message) {
Toast.makeText(this, message, Toast.LENGTH_LONG).show();
}
}
I based the project off a project I found on github and changed some things around. I'm not trying to develop an app for distribution just a one-off little app for my own use. I'm using wakeLock because the Android Wear code is in a Listener Service (there is no activity so I don't have a Window to obtain and set flags on or anything). I'm testing using an Asus tablet and a Round Android Wear emulator. Turning on/off the display is such a simple function that I couldn't find support for in any third-party apps that I looked at and the fact that it is giving me this much trouble is completely maddening. Any ideas would be greatly appreciated!
WearableListenerService lifecycle is managed by the system, so you can't be sure that your fields (specifically first and wakeLock retain their values between different messages. And in fact, in my code this service dies after every message. So probably you create a new wakelock each time and try to lock or unlock it, instead of working with the previous one.
To solve this problem you can create a different service with known lifecycle and send commands to it from your WearableListenerService.
P.s. Please, post logcat output with such kind if question.

Android GCM not send notification message to device

I have facing problem in getting notification message from GCM Server.Device will get notification correctly when it not idle or in running state but when device goes idle for 10-15 minutes at that time device not able to get notification and also all registered devices are not gets notification from GCM server.How to resolve this problem?
Normally, your app need to wake when it sleeps.
Put this into your manifest file to wake your device when the message is received
<uses-permission android:name="android.permission.WAKE_LOCK" />
Add java class name WakeLocker.java
public abstract class WakeLocker {
private static PowerManager.WakeLock wakeLock;
public static void acquire(Context context) {
if (wakeLock != null) wakeLock.release();
PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
wakeLock = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK |
PowerManager.ACQUIRE_CAUSES_WAKEUP |
PowerManager.ON_AFTER_RELEASE, "WakeLock");
wakeLock.acquire();
}
public static void release() {
if (wakeLock != null) wakeLock.release(); wakeLock = null;
}
}
Call the above code in 'private final BroadcastReceiver mHandleMessageReceiver = new BroadcastReceiver()' that might be in your MainActivity.java
private final BroadcastReceiver mHandleMessageReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String newMessage = intent.getExtras().getString(EXTRA_MESSAGE);
// Waking up mobile if it is sleeping
WakeLocker.acquire(getApplicationContext());
/**
* Take appropriate action on this message
* depending upon your app requirement
* For now i am just displaying it on the screen
* */
// Showing received message
lblMessage.append(newMessage + "\n");
Toast.makeText(getApplicationContext(), "New Message: " + newMessage, Toast.LENGTH_LONG).show();
// Releasing wake lock
WakeLocker.release();
}
};
Thank This source
Hope this helps

wifi connection is getting closed when device is going in sleep/locked state [duplicate]

I have a service which polls a server at certain intervals. I use an AlarmManager and a BroadcastReceiver to start the service. My problem is that after a certain duration, even though the Wifi is still enabled, but for some reason, my application can't contact the server. I get an "Unreachable network" error.
Note that I've already acquired a partial wake lock as well as a wifilock.
Here's my code for the BroadcastReceiver.
public class ServiceAlarmBroadcastReceiver extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
WakeLock wakeLock = null;
WifiLock wifiLock = null;
try {
PowerManager pm = (PowerManager) context
.getSystemService(Context.POWER_SERVICE);
// acquire a WakeLock to keep the CPU running
wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
"MyWakeLock");
if(!wakeLock.isHeld()){
wakeLock.acquire();
}
Log.i("ServiceAlarmBroadcastReceiver", "WakeLock acquired!");
WifiManager wm = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
wifiLock = wm.createWifiLock(WifiManager.WIFI_MODE_FULL , "MyWifiLock");
if(!wifiLock.isHeld()){
wifiLock.acquire();
}
Log.i("ServiceAlarmBroadcastReceiver", "WifiLock acquired!");
context.startService(new Intent(context, ThePollerService.class));
} finally {
// release the WakeLock to allow CPU to sleep
if (wakeLock != null) {
if (wakeLock.isHeld()) {
wakeLock.release();
Log.i("ServiceAlarmBroadcastReceiver", "WakeLock released!");
}
}
// release the WifiLock
if (wifiLock != null) {
if (wifiLock.isHeld()) {
wifiLock.release();
Log.i("ServiceAlarmBroadcastReceiver", "WiFi Lock released!");
}
}
}
}
}
The problem with the code posted here is that you acquire and release the WakeLock and WifiLock from right inside of your receiver. Unless you are completing your entire task inside of the onStart of your service (which if you are, why even bother having a service???), the locks will be released before your polling task completes.
I would suggest changing your implementation to something like the following:
Have broadcast receiver start service (and that is all)
Have service acquire wake locks and kick off the thread to do your polling operation. The most appropriate spot would be your service onCreate)
After your polled operation is complete, you should stop your polling service
In the onDestroy of your service, you should release the locks you acquired in onStart
Thanks to Tom, I was able to resolve this issue. Here's the code:
Settings.System.putInt(getContentResolver(),
Settings.System.WIFI_SLEEP_POLICY,
Settings.System.WIFI_SLEEP_POLICY_NEVER);
Under the WiFi Settings, Menu Key, Advanced Options theirs the WIFI_SLEEP_POLICY option list which when set to never will keep the WiFi connection open while the phone is asleep.
You can manipulate this under Settings.System Package.
http://developer.android.com/reference/android/provider/Settings.System.html#WIFI_SLEEP_POLICY
Hope this helps,
Tom
A little edit to javauser's answer:
private void setNeverSleepPolicy() {
try {
ContentResolver cr = getContentResolver();
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.JELLY_BEAN) {
int set = android.provider.Settings.System.WIFI_SLEEP_POLICY_NEVER;
android.provider.Settings.System.putInt(cr, android.provider.Settings.System.WIFI_SLEEP_POLICY, set);
} else {
int set = android.provider.Settings.Global.WIFI_SLEEP_POLICY_NEVER;
android.provider.Settings.System.putInt(cr, android.provider.Settings.Global.WIFI_SLEEP_POLICY, set);
}
} catch (Exception e) {
e.printStackTrace();
}
}

Categories

Resources