Android Service stop working when android device is sleep - android

I am working with an android service. I want the service run always even when device is sleep. But my service is stop when my device is sleep. this is my code
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
isRunning = true;
mythread = new Thread() {
#Override
public void run() {
while (isRunning) {
turnOnScreen(60000*3);
//Download some information by android Volley request
downloadInfo();
try {
Thread.sleep(60000*2);
} catch (InterruptedException e) {
isRunning = false;
e.printStackTrace();
}
}
}
};
if (isRunning) {
if (!mythread.isAlive()) {
mythread.start();
}
}
return START_REDELIVER_INTENT;
}
And turnOnScreen method is
private void turnOnScreen(long milliSeconds){
PowerManager mgr = (PowerManager)this.getSystemService(this.POWER_SERVICE);
PowerManager.WakeLock wakeLock = mgr.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "MyWakeLock");
wakeLock.acquire(milliSeconds);
}
Please help anyone. Thanks in advance.

I want the service run always even when device is sleep
Your users may disagree with this. Certainly lots of users have complained about poor battery life, which is why Google and device manufacturers have taken steps to stop developers from doing things like this.
But my service is stop when my device is sleep
On Android 8.0+, your service will stop running after one minute.
On Android 6.0+, your approach will not work once the device goes into Doze mode. Some manufacturers implemented similar restrictions prior to Android 6.0. Plus, if downloadInfo() takes longer than a minute, the device may fall asleep between wakelocks.

Related

Foreground Service killed on Huawei (GRA-UL00) - Protected Apps Enabled

My foreground sticky service is killed after a few hours without being restarted. I know this has been asked a couple of times, and I have read and verified all the checks on my device. Its important to note that this seems to occur only on Huawei devices.
So allow me to provide the following details.
Periodic Service
public class PeriodicService extends Service {
#Override
public void onCreate() {
super.onCreate();
acquireWakeLock();
foregroundify();
}
private void foregroundify() {
// Omitted for brevity. Yes it does starts a foreground service with a notification
// verified with adb shell dumpsys activity processes > tmp.txt
// entry in tmp.txt => "Proc # 1: prcp T/S/SF trm: 0 14790:my.app.package.indentifier/u0a172 (fg-service)"
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
acquireWakeLock();
if (!isServiceRunningInForeground(this, this.getClass())){
foregroundify();
}
PeriodicAlarmManager alarmManager = PeriodicAlarmManager.get(this);
alarmManager.setAlarm();
return START_STICKY; // after a few hours, service terminates after this returns. verified in my local logs
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onDestroy() {
releaseWakeLock();
stopForeground(true);
super.onDestroy();
}
}
PeriodicAlarmManager
public void setAlarm() {
Intent intent = new Intent(mContext, PeriodicAlarmReceiver.class);
intent.setAction("repeat");
mAlarmIntent = PendingIntent.getBroadcast(mContext, 0, intent, 0);
mAlarmManager.cancel(mAlarmIntent);
long triggerAtMillis = System.currentTimeMillis() + ALARM_INTERVAL_MINUTES;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) {
mAlarmManager.setExact(AlarmManager.RTC_WAKEUP, triggerAtMillis, mAlarmIntent);
} else {
mAlarmManager.set(AlarmManager.RTC_WAKEUP, triggerAtMillis, mAlarmIntent);
}
ComponentName receiver = new ComponentName(mContext, PeriodicBootReceiver.class);
PackageManager pm = mContext.getPackageManager();
pm.setComponentEnabledSetting(receiver,
PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
PackageManager.DONT_KILL_APP);
}
PeriodicAlarmReceiver
public class PeriodicAlarmReceiver extends WakefulBroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Intent service = new Intent(context, PeriodicService.class);
service.putExtra("source", "PeriodicAlarmReceiver");
intent.getAction()));
startWakefulService(context, service);
}
}
Application
public class MyApp extends Application {
#Override
public void onCreate() {
super.onCreate();
}
#Override
public void onLowMemory(){
super.onLowMemory(); // never gets called
}
#Override
public void onTrimMemory(int level){
super.onTrimMemory(level); // only gets called on app launch
}
#Override
public void onTerminate() {
super.onTerminate();
}
}
adb shell dumpsys activity processes > tmp.txt
Entry in tmp.txt => "Proc # 1: prcp T/S/SF trm: 0 14790:my.app.package.indentifier/u0a172 (fg-service)"
Above Entry is based on accepted answer here: Foreground service being killed by Android
Added MyApp to protected app list in Settings-> Advanced Settings -> Battery Manager -> Protected Apps (Allow app to keep running after screen is turned off)
Used Performance (lowest setting) in Settings-> Advanced Settings -> Power Plan (Performance)
Device Information
Model Number: HUAWEI GRA-UL00
EMUI Version: EMUI 4.0.1
Android Version: 6.0
Other Notes:
Low Memory, onTrimMemory is not called prior to termination. In any case, I stripped the app to its bare minimum just to keep the app alive in the background, so memory should not be an issue here.
Sticky Service is never restarted unless user explicitly re-launches the app.
Alarm Manager is not called to restart/recreate service. setExactAndAllowWhileIdle() does not work either, and should be irrelevant since the service is a foreground priority service, and hence should not be affected by doze mode.
Service can only run at the maximum of 12 hours before being terminated. Battery was above 65% when this happened.
It is a requirement to keep the service running indefinitely as this app is for a research project.
Is there anything else I can do or is this a specific Huawei Android modification that the developer can do nothing about. To reiterate, this issue only happens on Huawei devices.
Appreciate any additional insight on this!
Are you absolutely sure you need the wakelock? I have a similar service and I have noticed that it works even without the wakelock. This post claims that the killer is the wakelock.
I have tried with my process which used to be killed in minutes and it has now been running for hours.
Huawei -> have a battery settings, but it's not about power save mode. under this battery settings screen, there is sub-menu call "Protected App" (not sure the name). you need to allow your app to be protected to prevent Huawei kill app after lock the screen.
It sounds like your app is being killed by Huawei PowerGenie because it holds a wake lock indefinitely. If you can't avoid using a wake lock, please see my answer to a similar question for a workaround.

Intent Service not working in doze mode

One of my peer developer has written an intent service that makes an API call and then sleeps for 2 mins. After waking up, it sends again.
Below is the code:
public class GpsTrackingService extends IntentService {
....
#Override
protected void onHandleIntent(Intent intent) {
do{
try{
//make API call here
//then go to sleep for 2 mins
TimeUnit.SECONDS.sleep(120);
} catch(InterruptedException ex){
ex.printStackTrace();
}
} while (preferences.shouldSendGps()); //till the user can send gps.
}
....
}
Manifest
<service android:name=".commons.GpsTrackingService" />
This is working fine when the phone is active. However, whenever the phone goes into doze mode it fails to wake.
Will using alarm manager with WAKE permission solve this?
I have just got the code base and need to fix this within today. It'll be great if someone can help.
As the documentation says:
In Doze mode, the system attempts to conserve battery by restricting
apps' access to network and CPU-intensive services. It also prevents
apps from accessing the network and defers their jobs, syncs, and
standard alarms.
Periodically, the system exits Doze for a brief time to let apps
complete their deferred activities. During this maintenance window,
the system runs all pending syncs, jobs, and alarms, and lets apps
access the network.
In few words, while in Doze mode the system suspends network accesses, ignores Wake Locks, stops acquiring data from sensors, defers AlarmManager jobs to the next Doze maintenance window (which are progressively less frequently called), also WiFi scans, JobScheduler jobs and Sync adapters do not run.
Neither setAndAllowWhileIdle() nor setExactAndAllowWhileIdle() can fire alarms more than once per 9 (?) minutes, per app.
And it seems that the Foreground Services are also involved into this "Doze Drama", at least in MarshMellow (M).
To survive in this situation, tons of applications need to be at least rewiewed. Can you imagine a simple mp3 player which stops playing music when the device enters in Doze Mode?
Doze mode starts automatically, when the device is unplugged from the power supply and left on the table for about 1 hour or so, or even earlier when the user clicks the power button to power down the screen, but I think this could depend by the device manufacturer too.
I tried a lot of countermeasures, some of them really hilarious.
At the end of my tests I reached a possible solution:
One possible (and maybe the only) way to have your app running even when the host device is in Doze mode, is basically to have a ForegroundService (even a fake one, doing no jobs at all) running in another process with an acquired partial WakeLock.
What you need to do is basically the following (you could create a simple project to test it):
1 - In your new project, create a new class which extends Application (myApp), or use the
main activity of the new project.
2 - In myApp onCreate() start a Service (myAntiDozeService)
3 - In myAntiDozeService onStartCommand(), create the Notification
needed to start the service as a foreground service, start the
service with startForeground(id, notification) and acquire the
partial WakeLock.
REMEMBER! This will work, but it is just a starting point, because you have to be careful with the "Side Effects" this approach will generate:
1 - Battery drain: The CPU will work for your app forever if you
don't use some strategy and leave the WakeLock always active.
2 - One notification will be always shown, even in the lockscreen,
and this notification cannot be removed by simply swiping it out, it
will be always there until you'll stop the foreground service.
OK, let's do it.
myApp.java
public class myApp extends Application {
private static final String STARTFOREGROUND_ACTION = "STARTFOREGROUND_ACTION";
private static final String STOPFOREGROUND_ACTION = "STOPFOREGROUND_ACTION";
#Override
public void onCreate() {
super.onCreate();
// start foreground service
startForeService();
}
private void stopForeService() {
Intent service = new Intent(this, myAntiDozeService.class);
service.setAction(STOPFOREGROUND_ACTION);
stopService(service);
}
private void startForeService(){
Intent service = new Intent(this, myAntiDozeService.class);
service.setAction(STARTFOREGROUND_ACTION);
startService(service);
}
#Override
public void onTerminate() {
stopForeService();
super.onTerminate();
}
}
myAntiDozeService.java
public class myAntiDozeService extends Service {
private static final String TAG = myAntiDozeService.class.getName();
private static boolean is_service_running = false;
private Context mContext;
private PowerManager.WakeLock mWakeLock;
private static final int NOTIFICATION_ID = 12345678;
private static final String STARTFOREGROUND_ACTION = "STARTFOREGROUND_ACTION";
private static final String STOPFOREGROUND_ACTION = "STOPFOREGROUND_ACTION";
#Override
public void onCreate() {
super.onCreate();
mContext = getApplicationContext();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (!is_service_running && STARTFOREGROUND_ACTION.equals(intent.getAction())) {
Log.i(TAG, "Received Start Foreground Intent ");
showNotification();
is_service_running = true;
acquireWakeLock();
} else if (is_service_running && STOPFOREGROUND_ACTION.equals(intent.getAction())) {
Log.i(TAG, "Received Stop Foreground Intent");
is_service_running = false;
stopForeground(true);
stopSelf();
}
return START_STICKY;
}
#Override
public void onDestroy() {
releaseWakeLock();
super.onDestroy();
}
private void showNotification(){
Intent notificationIntent = new Intent(mContext, ActivityMain.class);
notificationIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
PendingIntent pendingIntent = PendingIntent.getActivity(mContext, 0, notificationIntent, 0);
Notification notification = new NotificationCompat.Builder(mContext)
.setContentTitle("myApp")
.setTicker("myApp")
.setContentText("Application is running")
.setSmallIcon(R.drawable.ic_launcher)
.setContentIntent(pendingIntent)
.build();
// starts this service as foreground
startForeground(NOTIFICATION_ID, notification);
}
public void acquireWakeLock() {
final PowerManager powerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
releaseWakeLock();
//Acquire new wake lock
mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG+"PARTIAL_WAKE_LOCK");
mWakeLock.acquire();
}
public void releaseWakeLock() {
if (mWakeLock != null && mWakeLock.isHeld()) {
mWakeLock.release();
mWakeLock = null;
}
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
}
AndroidManifest.xml changes.
In the AndroidManifest.xml add this permission:
<uses-permission android:name="android.permission.WAKE_LOCK" />
Don't forget to add the name of your app in the <application> tag:
<application
....
android:name=".myApp"
....
And finally add your foreground service running into another process:
<service
android:name=".myAntiDozeService"
android:process=":MyAntiDozeProcessName">
</service>
A couple of notes.
In the previous example, the notification created, when clicked,
opens the ActivityMain activity of your test project.
Intent notificationIntent = new Intent(mContext, ActivityMain.class);
but you can use another kind of intent too.
To test it, you have to add some job to be performed into your
ActivityMain.java, for example some repeating alarm (which was
normally stopped when the device falls in Doze Mode), or a ripetitive
network access, or a timed tone played, or.... whatever you want.
Remember that the job performed by the main activity has to run
forever because to test this AntiDoze you need to wait at least 1
hour to be sure the device enters in Doze Mode.
To enter in Doze mode, the device has to be quiet and unplugged, so
you can't test it while you are debugging. Debug your app first,
check that everything is running then stop it, unplug, restart the
app again and leave the device alone and quiet on your desk.
The adb commands suggested by the documentation to simulate Doze
and StandBy modes could and could not give you the right results
(it depends, I suppose, by the device manufacturer, drivers, bla
bla). Please make your tests in the REAL behaviour.
In my first test, I used an AlarmManager and a tone generator to play a tone every 10 minutes just to understand that my app was still active.
And it is still running from about 18 hours, breaking my ears with a loud tone exactly every 10 minutes. :-)
Happy coding!
One of my peer developer has written an intent service that makes an API call and then sleeps for 2 mins. After waking up, it sends again.
Only have a service running while it is actively delivering value to the user. Sitting around for two minutes, watching the clock tick, is not actively delivering value to the user.
Will using alarm manager with WAKE permission solve this?
That depends on what you mean by "solve this". You can use AlarmManager to request to get control every two minutes so that you can do work. While the device is in Doze mode, you will not actually get control every two minutes, but once per maintenance window.

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();
}
}

Stop the Service after the Vibrating the Phone in android?

I am trying to learn service in android.My goal is like that i will pass a LatLng Object to the service then service will do something with that and when the work will be finished then it will buzz the phone for sometime and stop.Finally the service will be finished.Now I have some query on that:
I will call the service from my app and user can close my app though
service is not finished.will service do the job initiated by my app or
it will also finish??
What i studied take me here that service will continue to execute and one thing i don't have to return anything back to activity who has initiated the service.I have written some code.Can anyone help me out??
public class MapService extends Service {
private boolean isRunning = false;
#Override
public void onCreate() {
Log.i(TAG, "Service onCreate");
isRunning = true;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i(TAG, "Service onStartCommand");
//Creating new thread for my service
//Always write your long running tasks in a separate thread, to avoid ANR
new Thread(new Runnable() {
#Override
public void run() {
//here i will do my work
if(isRunning){
Log.i(TAG, "Service running");
}
}
//Stop service once it finishes its task
stopSelf();
}
}).start();
return Service.START_STICKY;
}
#Override
public IBinder onBind(Intent arg0) {
Log.i(TAG, "Service onBind");
return null;
}
#Override
public void onDestroy() {
isRunning = false;
Log.i(TAG, "Service onDestroy");
}
}
Will it work if user closes the app??
Yes this service will run even if user will close app.It is also possible if android system demands memory service will be stopped but it will restart again
as you have set your flag START_STICKY in your onStartCommand.
On Android KitKat and above(4.4+), the service will be stopped if user swipe kills the application and it won't be restarted by the system. See this discussion(1). If the application was stopped by Android system itself (for low resources), the service will be restarted after a while(use START_STICKY flag).
On Android 4.3 and below, service will be restarted irrespective of whether application was stopped by system or user(use START_STICKY flag).
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
// We want this service to continue running until it is explicitly stopped, so return sticky.
return START_STICKY;
}

Wake locks android service recurring

I have this application that needs to run a service (background) that beeps periodically.
The phone needs to beep the entire day for 5 seconds every one minute (used a handler in the service). I have implemented this service which does this perfectly, but when the phone goes into deep sleep mode, the execution stops of this handler stops. Using this answer from the question in SO, I managed to use wake locks and it works fine. But when I explicitly put the phone in deep sleep mode, the handler stops executing. Where do I place the wakelock in the service. Code snippet below.
public class PlaySound extends Service{
PowerManager.WakeLock wl ;
PowerManager pm;
private SoundManager mSoundManager;
boolean wakeUpFlag = false;
#Override
public void onCreate(){
super.onCreate();
mSoundManager = new SoundManager();
mSoundManager.initSounds(getBaseContext());
mSoundManager.addSound(1, R.raw.sound);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
startservice();
return START_STICKY;
}
private void startservice() {
System.out.println("Started the service");
timer.scheduleAtFixedRate( new TimerTask() {
public void run() {
toastHandler.sendEmptyMessage(0);
}
}, 0, 60000);
}
private final Handler toastHandler = new Handler()
{
#Override
public void handleMessage(Message msg)
{
result =start();
System.out.println("result"+result);
close();
}
};
protected void close() {
try {
if(wakeUpFlag){
wl.release();
System.out.println("Released the wakelock");
}
if(!pm.isScreenOn()){
System.out.println("Screen is off - back to sleep");
pm.goToSleep(1000);
}
else{
System.out.println("Screen is on - no need to sleep");
}
bs.close();
writer.close();
System.out.println("Closed socket and writer");
System.out.println("Size of file:"+f.length()/1024);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
public void start(){
try{
wakeUpFlag = false;
pm = (PowerManager)getSystemService(Context.POWER_SERVICE);
if(!pm.isScreenOn()) {
wakeUpFlag = true;
wl = pm.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK | PowerManager.ON_AFTER_RELEASE,"CollectData");
System.out.println("Screen off - wake lock acquired");
wl.acquire();
}
else{
System.out.println("Screen on - no need of wake lock");
}
}
catch(Exception e){
e.printStackTrace();
}
mSoundManager.playSound(1);
}
I dont think you are using the correct flag accorinding to the android documentation fior PowerManager:
*If you hold a partial wakelock, the CPU will continue to run, irrespective of any timers and even after the user presses the power button. In all other wakelocks, the CPU will run, but the user can still put the device to sleep using the power button.
In other words, try using PARTIAL_WAKE_LOCK as this is the only one that gurantees the cpu to run
Follow the pattern Mark Murphy provides with the WakefulIntentService. I would suggest picking up his books, not only for the detailed explanation of this class and example he includes in one of them, but for the other wealth of information you'll find in them.
I just recently implemented this pattern for my main app and this class works like a charm.
I think you'd be better off using android.app.AlarmManager to schedule a wakeup alarm. Be careful though - you don't want to do any long-running work in your onReceive() method as that's normally called on the main thread, and will hang your activity. You'll still need to acquire the wakelock for the duration of your task to prevent the phone sleeping part-way through.

Categories

Resources