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

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.

Related

Service does not restart after being killed by the system

Tell me, can anyone come across such a problem. Regular service:
public class ContactChangeService extends Service {
public ContactChangeService() {
}
#Override
public void onCreate() {
super.onCreate();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Intent notificationIntent = new Intent(this, MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this,
0, notificationIntent, 0);
Notification notification = new NotificationCompat.Builder(this, CONTACT_CHANGE_CHANNEL_ID)
.setContentTitle("itle")
.setSmallIcon(R.drawable.ic_black_list)
.setContentText("Message")
.setContentIntent(pendingIntent)
.build();
startForeground(1546644, notification);
return START_STICKY;
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onDestroy() {
super.onDestroy();
}}
This is how the service is started from a fragment:
Intent serviceIntent = new Intent(getContext(), ContactChangeService.class);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
ContextCompat.startForegroundService(getActivity(), serviceIntent);
} else {
getActivity().startService(serviceIntent);
}
To clearly see how the system works with services, I chose for testing, probably the weakest smartphone with a small amount of RAM, FinePower. One has only to run several applications, the memory in the RAM runs out and the service is killed by the system. But, despite the START_STICKY value in onStartCommand, the service does not start again, even if there is enough RAM again. What could be the problem? Thanks in advance.
There are some devices, especially low-end devices, that will not permit apps to run indefinitely in the background (for battery-saving purposes). These devices do NOT automatically restart services, even if you return START_STICKY from onStartCommand(). Usually on these devices, there is way to manually add your app to a list of "protected apps" or a list of "apps allowed to run in the background". Once you've added your app to this list, Android will automatically restart it, as designed. There is no way to automatically add your app to this list, the user must do it manually. Usually there is a way to do this in the Settings, either under "power management", "Battery management", or "security". I don't know the device you are testing so I cannot tell you exactly where to find the setting.
See the following for more info:
BroadcastReceiver works for a while, then stops
"Protected Apps" setting on Huawei phones, and how to handle it

Continually Running Background Service

I'm targeting sdk version 27 with a minimum version of 19 and trying to get a service that runs continuously in the background. I tried different service start options but it still got killed with the app. I tried using a BroadcastReceiver to start the service when it got killed but that gave me an error saying that the app was in the background and couldn't start a service so I tried using the JobScheduler and that gave me the same error. How is this supposed to be done? For example, if I were making a pedometer app, how could I keep that running in the background?
In oreo release Android defined limits to background services.
To improve the user experience, Android 8.0 (API level 26) imposes
limitations on what apps can do while running in the background.
Still if app need to run its service always, then we can create foreground service.
Background Service Limitations: While an app is idle, there are limits
to its use of background services. This does not apply to foreground
services, which are more noticeable to the user.
So create a foreground service. In which you will put a notification for user while your service is running. See this answer (There are many others)
Now what if you don't want a notification for your service. A solution is for that.
You can create some periodic task that will start your service, service will do its work and stops itself. By this your app will not be considered battery draining.
You can create periodic task with Alarm Manager, Job Scheduler, Evernote-Jobs or Work Manager.
Instead of telling pros & cons of each one. I just tell you best. Work manager is best solution for periodic tasks. Which was introduced with Android Architecture Component.
Unlike Job-Scheduler(only >21 API) it will work for all versions.
Also it starts work after a Doze-Standby mode.
Make a Android Boot Receiver for scheduling service after device boot.
I created forever running service with Work-Manager, that is working perfectly.
Since Android 8.0 many background service limitations have been introduced.
Two solutions:
if you need to get total control of task and execution timing, you have to choose Foreground Service.
Pros: your app will be considered to be alive, then is more unlikely that the os will kill it to free resources.
Cons: your user will always see the Foreground Notification.
if you need to schedule periodically task, then Work Manager (introduced in Google I/O 18) is the best solution. This component choose the best possible scheduler (Jobscheduler, JobDispatcher, AlarmManager..). Keep in mind that work manager APIs are useful only for the tasks that require guaranteed execution and they are deferrable.
Ref: Android Dev Documentation
The only solution I would suggest is using Firebase Cloud Messages.
Or foreground services.
Using BroadcastReciever we can run backgrouund service continuously, but if it will get killed , destroy automatically re-instance the old service instance
When service stops forcefully it will call onDestroy() method, in this case use one receiver and send one broadcast when ever service destroy and restart service again. in thee following method com.android.app is custom action of reciever class which extends BroadcastReciever
public void onDestroy() {
try {
myTimer.cancel();
timerTask.cancel();
} catch (Exception e) {
e.printStackTrace();
}
Intent intent = new Intent("com.android.app");
intent.putExtra("valueone", "tostoreagain");
sendBroadcast(intent);
}
and in onReceive Method
#Override
public void onReceive(Context context, Intent intent) {
Log.i("Service Stoped", "call service again");
context.startService(new Intent(context, ServiceCheckWork.class));
}
In case device is restarted then we have onBootCompleted action for receiver to catch
When you are targeting SdkVersion "O"
In MainActivity.java define getPendingIntent()
private PendingIntent getPendingIntent() {
Intent intent = new Intent(this, YourBroadcastReceiver.class);
intent.setAction(YourBroadcastReceiver.ACTION_PROCESS_UPDATES);
return PendingIntent.getBroadcast(this, 0, intent,
PendingIntent.FLAG_UPDATE_CURRENT);
}
here we use PendingIntent with BroadcastReceiver and This BroadcastReceiver has already been defined in AndroidManifest.xml.
Now in YourBroadcastReceiver.java class which contains an onReceive() method:
Override
public void onReceive(Context context, Intent intent) {
if (intent != null) {
final String action = intent.getAction();
if (ACTION_PROCESS_UPDATES.equals(action)) {
NotificationResult result = NotificationResult.extractResult(intent);
if (result != null) {
List<Notification> notifications = result.getNotification();
NotificationResultHelper notificationResultHelper = new
NotificationResultHelper(
context, notifications);
// Save the notification data to SharedPreferences.
notificationResultHelper.saveResults();
// Show notification with the notification data.
notificationResultHelper.showNotification();
Log.i(TAG,
NotificationResultHelper.getSavedNotificationResult(context));
}
}
}
}
as you say:
I tried using a BroadcastReceiver to start the service when it got
killed but that gave me an error saying that the app was in the
background and couldn't start a service
in Oreo when you are in background and you want to start a service that service must be a foreground service use this code:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
context.startForegroundService(intent);
} else {
context.startService(intent);
}
if you use this code in Oreo you have a few seconds in onStartCommand to start foreground otherwise your service considered as not responding and may be force close by user (in Android 8 or above)
There is no need to use BroadcastReceiver to start service after it is closed it is enough to just return START_STICKY or START_REDELIVER_INTENT from onStartCommand of your service to restart service after it is closed
A working hack for this is to simply start a foreground service which is only visible for the fraction of a second and starts your background service. In the background service you'd then periodically start the foreground service.
Before I give an example you should really ask yourself if this is the way to go for you, there might be other solutions to given problems (like using JobIntentService etc.); and keep in mind that this is a hack, it might be patched some time around and I'd generally not use it (I tested it with screen off and battery saving enabled though and it stayed alive the whole time - but this might prevent your device from dozing.. again, this is a dirty hack!)
Example:
public class TemporaryForegroundService extends Service {
public static final int NOTIFICATION_ID = 666;
private static Notification notification;
#Override
public void onCreate() {
super.onCreate();
if(notification == null)
notification = new NotificationCompat.Builder(this, NotificationChannels.importantChannel(this)).
setSmallIcon(R.mipmap.ic_launcher).setContentTitle("The unseen blade").setContentText("If you see me, congrats to you.").build();
startForeground(NOTIFICATION_ID, notification);
startService(new Intent(this, PermanentBackgroundService.class));
stopForeground(true);
stopSelf();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_NOT_STICKY;
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
}
public class PermanentBackgroundService extends Service {
private Runnable keepAliveRunnable = new Runnable() {
#Override
public void run() {
keepServiceAlive();
if(handler != null) handler.postDelayed(this, 15*1000);
}
};
private Handler handler;
public void onCreate(){
handler = new Handler();
handler.postDelayed(keepAliveRunnable, 30* 1000);
}
public void onDestroy() {
super.onDestroy();
keepServiceAlive();
}
private void keepServiceAlive() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
startForegroundService(new Intent(PermanentBackgroundService.this, TemporaryForegroundService .class));
} else {
startService(new Intent(PermanentBackgroundService.this, TemporaryForegroundService .class));
}
}
}

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.

How to detect application exit on android?

How to execute some code on application exit? I want to delete temp data on application exit. By application exit i mean that app is not running minimized in background and its totally gone.
I tried to make service that runs in separate process, the service is checking if app process is not running it should delete temp folder. With this approach temp folder is not always deleted because process is still running with the lowest priority.
I can't do this in OnDestroy().
Service code:
[Service(Process = "com.lobomonitor")]
[IntentFilter(new string[] { "com.androidgui.ProcessMonitorService" })]
public class ProcessMonitorService : Service
{
public override StartCommandResult OnStartCommand(Intent intent, StartCommandFlags flags, int startId)
{
Thread processThread = new Thread(() =>
{
ActivityManager actManager = (ActivityManager) this.GetSystemService(ActivityService);
while (true)
{
Thread.Sleep(1000);
IList<ActivityManager.RunningAppProcessInfo> procList = actManager.RunningAppProcesses;
procList.Any(i => i.ProcessName.Equals("com.androidgui"));
if (!procList.Any(i => i.ProcessName.Equals("com.androidgui")))
{
FolderManager.Singleton.DeleteTempFolder();
break;
}
}
});
processThread.Start();
return StartCommandResult.RedeliverIntent;
}
public override IBinder OnBind(Intent intent)
{
return null;
}
}
I don't know if that help, but if you kill your app, then service that runs in background calls method:
#Override
public void onTaskRemoved(Intent rootIntent){
super.onTaskRemoved(rootIntent);
}
For example I had once app that was running service. When I killed app - service died too, but I wanted it to stay alive. By using onTaskRemoved I was able to schedule restart of service:
#Override
public void onTaskRemoved(Intent rootIntent){
Intent restartServiceIntent = new Intent(getApplicationContext(), this.getClass());
restartServiceIntent.setPackage(getPackageName());
PendingIntent restartServicePendingIntent = PendingIntent.getService(getApplicationContext(), 1, restartServiceIntent, PendingIntent.FLAG_ONE_SHOT);
AlarmManager alarmService = (AlarmManager) getApplicationContext().getSystemService(Context.ALARM_SERVICE);
alarmService.set(
AlarmManager.ELAPSED_REALTIME,
SystemClock.elapsedRealtime() + 1000,
restartServicePendingIntent);
super.onTaskRemoved(rootIntent);
}
Effect was -> I am killing my app -> Service see that tasks are being removed and calls onTaskRemoved -> I am scheduling restart of service in 1 sec -> Service dies -> After one sec it wakes up -> RESULT: App is killed, i executed code that restarted my service so it is still running in background (visible only in preferences -> applications as process)
http://developer.android.com/reference/android/app/Service.html
void onTaskRemoved(Intent rootIntent)
This is called if the service is currently running and the user has removed a task that comes from the service's application.
My experience shows that most apps do not really need an exit-callback of the sort
you are describing.
The Android way, which usually works fine, is of component-level (Activity, Service..)
lifecycle management.
Some apps allow for an 'Exit' functionality (via button, menu etc.) that, when activated
by the user, allows the app to close all open components and basically go down.
But, if exit-callback is really what you want, the closest thing to it would probably
be to create a dedicated service with no logic other than onDestroy() function
and to activate it at app startup without ever closing it!
class ExitListenerService extends Service {
#Override
public void onDestroy() {
super.onDestroy();
// App exit logic here. Not deterministic!
}
}
The odds are such a service will probably be the last component to be reclaimed by the
operating system. This should work in most cases, it worked fine for me. But it is not
100% guaranteed.
But.. if you must have a bullet proof solution the only other way I know is to create a peer application, call it watchdog, that will periodically wake up to check weather or not your main app
is still running and, if not running, will activate the exit logic.
To run this last check you will need to call
List<RunningAppProcessInfo> runningApps = activityManager.getRunningAppProcesses();
and iterate over runningApps looking for your own.

Android: Re-invoke application if task manager kill

Application thread get close if its killed by task manager. Need to re-invoke application as though its killed by other application or task manager. Any idea?
You have to run background service with START_STICKY command.
Just extends Service and override onCommand like this :
#Override
public int onStartCommand(Intent intent,int flags,int startId) {
super.onStartCommand(intent, flags, startId);
return START_STICKY;
}
Like this your Service is restart when it's close (by system or anything else)
You just have now check on your service (onCreate for example) if application is running or not and launch it again if not. I suppose PackageManager let you check this or simply put a static boolean is_alive to see if your activity is always running.
Regards
Jim
Bug in Android 2.3 with START_STICKY
I needed to keep alive a Service with all my forces. If the service is running anytime you can pop the UI.
onDestroy()
it will re-launch.
Can't be uninstalled the app, because it has a Device Administrator.
It is a kind of parental control, the user knows it is there.
Only way to stop is to remove the Device Admin, and uninstall it, but removing Device Admin will lock the phone as Kaspersky how it does.
There are a loot of braodcast receivers, such as boot finshed, user presen, screen on, screen off... , many other, all starting the service, you can do it with UI too. Or in the service check if your activity alive , visible, if not, than pop it.
I hope you will use with good reason the info!
Edit: Restart service code snippet:
// restart service:
Context context = getApplicationContext();
Intent myService = new Intent(context, MyService.class);
context.startService(myService);
Edit2: add spippet to check if the service is running in ... a load of Broadcasts
public static boolean isMyServiceRunning(Context context) {
ActivityManager manager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
for (RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
if (MyService.class.getName().equals(service.service.getClassName())) {
Log.d("myTag", "true");
return true;
}
}
Log.d("myTag", "false");
return false;
}
Edit3 other service start:
public static void startTheService(Context context) {
Intent myService = new Intent(context, MyService.class);
context.startService(myService);
}
Dont't forget Android 2.3 bug: do the logic for initialization in
#Override
public void onCreate()
and not in:
#Override
public int onStartCommand(Intent intent, int flags, int startId)
While look at Google IO official product source code I have found the following
((AlarmManager) context.getSystemService(ALARM_SERVICE))
.set(
AlarmManager.RTC,
System.currentTimeMillis() + jitterMillis,
PendingIntent.getBroadcast(
context,
0,
new Intent(context, TriggerSyncReceiver.class),
PendingIntent.FLAG_CANCEL_CURRENT));
URL for code
You can start a sticky service and register an alarm manager that will check again and again that is your application is alive if not then it will run it.
You can also make a receiver and register it for <action android:name="android.intent.action.BOOT_COMPLETED" /> then you can start your service from your receiver. I think there should be some broadcast message when OS or kills some service/application.
Just to give you a rough idea I have done this and its working
1) register receiver
Receiver Code:
#Override
public void onReceive(Context context, Intent intent) {
try {
this.mContext = context;
startService(intent.getAction());
uploadOnWifiConnected(intent);
} catch (Exception ex) {
Logger.logException(ex);
Console.showToastDelegate(mContext, R.string.msg_service_starup_failure, Toast.LENGTH_LONG);
}
}
private void startService(final String action) {
if (action.equalsIgnoreCase(ACTION_BOOT)) {
Util.startServiceSpawnProcessSingelton(mContext, mConnection);
} else if (action.equalsIgnoreCase(ACTION_SHUTDOWN)) {
}
}
Service Code:
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Logger.logInfo("Service Started onStartCommand");
return Service.START_STICKY;
}
I prefer doing nothing in onStartCommand because it will get called each time you start service but onCreate is only called 1st time service is started, so I do most of the code in onCreate, that way I don't really care about weather service is already running or not.
according to #RetoMeyer from Google, the solution is to make the app "sticky".
for this, you must establisH START_STICKY in your intent service management.
check this reference from developer android
Yes, Once memory low issue comes android os starts killing application to compensate the required memory. Using services you can achieve this, your service should run parallely with your application but see, some of the cases even your service will be also killed at the same time. After killing if memory is sufficient android os itself try to restart the application not in all the cases. Finally there is no hard and fast rule to re-invoke your application once killed by os in all the cases it depends on os and internal behaviours.

Categories

Resources