I'm using Eclipse's Paho android library. This library internally starts a Service to fetch data. Now when my app is in background and push notification comes, Paho's service works well for pre-oreo devices. But on Oreo device, this work for few minutes duration after app goes to the background state. After this duration, although I'm sending high priority GCM message, service won't starts and gives warning in logcat Background start not allowed. As stated in offical docs, for high priority GCM messages, app becomes whitelisted for few minutes. In this case, it should work for high priority GCM message.
From my understanding app should become whitelisted whenever high priority GCM arrives. Is it correct?
To be ready for Android O:
1) Instead of IntentService; your service needs to extend JobIntentService.
2) Instead of onHandleIntent; you need to use onHandleWork.
3) Instead of startService; you need to use enqueueWork.
Check this out.
https://developer.android.com/reference/android/support/v4/app/JobIntentService.html
When dealing with broadcasts, you need to make sure the intent is explicit.
private static void sendImplicitBroadcast(Context ctxt, Intent i) {
PackageManager pm=ctxt.getPackageManager();
List<ResolveInfo> matches=pm.queryBroadcastReceivers(i, 0);
for (ResolveInfo resolveInfo : matches) {
Intent explicit=new Intent(i);
ComponentName cn=
new ComponentName(resolveInfo.activityInfo.applicationInfo.packageName,
resolveInfo.activityInfo.name);
explicit.setComponent(cn);
ctxt.sendBroadcast(explicit);
}
}
This was from https://commonsware.com/blog/2017/04/11/android-o-implicit-broadcast-ban.html
Related
I read a lot of articles on forums, but wasn't able to make the "unkillable" background service work. I tried disabling the battery optimalization ( didn't work), making the foreground service ( since making app from api 24-31, didn't find solution on how to make it work, maybe the right way to do it), making the broadcast receiver - "restarter". (Of course this isn't all, but it is everything that has something to do with the service)
Manifest:
<service android:name="PathToService" android:foregroundServiceType="dataSync|location" />
<receiver
android:enabled="true"
android:name="PathToReciever"
android:label="RestartServiceWhenStopped">
</receiver>
Receiver:
#Override
public void onReceive(Context context, Intent intent) {
context.startService(new Intent(context, SERVICE));
}
Service:
#Override
public void onDestroy() {
Intent broadcastIntent = new Intent(this, SERVICE);
sendBroadcast(broadcastIntent);
}
incase if your whole problem is that the OS just randomly destroys the service after a while, you could returning START_STICKY in the onStartCommand method in the foreground service
according to Android Developers documentation :
START_STICKY
If the system kills the service after onStartCommand() returns, recreate the service and call onStartCommand(), but do not redeliver the last intent. Instead, the system calls onStartCommand() with a null intent unless there are pending intents to start the service. In that case, those intents are delivered. This is suitable for media players (or similar services) that are not executing commands but are running indefinitely and waiting for a job.
if that's the case then it gets solved by this code :
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
... \\ whatever your code contains here
return START_STICKY;
}
maybe that's why I'm telling you that I didn't notice that anything is killing my service rather during my tests.
N.B : take care that the lifetime of foreground services is higher than background ones, as since api 28 there's some restrictions on background services that might make it quite unusable for long work assignment that you should consider either switching to foreground services or use long-running-workers.
Foreground service
A foreground service performs some operation that is noticeable to the user. For example, an audio app would use a foreground service to play an audio track. Foreground services must display a Notification. Foreground services continue running even when the user isn't interacting with the app.
When you use a foreground service, you must display a notification so that users are actively aware that the service is running. This notification cannot be dismissed unless the service is either stopped or removed from the foreground.
Background
A background service performs an operation that isn't directly noticed by the user. For example, if an app used a service to compact its storage, that would usually be a background service.
Note: If your app targets API level 26 or higher, the system imposes restrictions on running background services when the app itself isn't in the foreground. In most situations, for example, you shouldn't access location information from the background. Instead, schedule tasks using WorkManager.
you can also check that question and its answer for more clarity
I need to be able to send my GPS-location to a server every time I receive a silent-push notification from Firebase. The timer for sending a notification is currently set to every 10 minutes. When the phone is charging this is not a problem, but when it's idle and the application is in the background, the onMessageReceived from FirebaseMessagingService is only called every few hours. This leads me to believe it has something to do with the new power management rules for Android 9.0. But for my application to work I need to be able to send my location every 10 minutes. Not just sometimes.
I have tried to set the battery optimisation to 'not optimised' using Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS
This does not seem to have any effect.
I also tried setting the priority of the Firebase notification to High. This works, but only for 10 messages per day, which means it's not a solution for my application. (Source: Power Management restrictions)
I am now trying to always have the application in the 'Active' bucket by opening a foregroundService. This should make sure the app is never in any other bucket, where the notifications can be deferred for a few hours.
An app is in the active bucket if the user is currently using the app, for example:
The app has launched an activity
The app is running a foreground service
The app has a sync adapter associated with a content provider used by a foreground app
The user clicks on a notification from the app
If an app is in the active bucket, the system does not place any restrictions on the app's jobs, alarms, or FCM messages.
(Source: Power Buckets Android9).
This does not seem like a solution I should want, though, since it might not be best practice. And it doesn't seem to work either anyways.
This is my onMessageReceived function:
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
Log.d(TAG, "From: " + remoteMessage.getFrom());
if (remoteMessage.getData().size() > 0) {
Log.d(TAG, "Message data payload: " + remoteMessage.getData());
Map<String, String> params = remoteMessage.getData();
JSONObject object = new JSONObject(params);
PushNotificationManager.getInstance().handlePushNotification(object, getApplicationContext());
}
}
Right now I am clueless as to why the Firebase messages do not enter the onMessageReceived function.
Tim,
I think that the main problem is with how you send the push notification and what is its content.
If you check here - https://firebase.google.com/docs/cloud-messaging/android/receive
you will see that if the message contains notification data and the app is at background then the push notification goes to the Notification area.
You need to send a push notification that contains only data:
(Here you can find more information about the different types - https://firebase.google.com/docs/cloud-messaging/concept-options#notifications_and_data_messages)
Here is what is the explanation how to trigger it-
In a trusted environment such as Cloud Functions or your app server, use the Admin SDK or the FCM Server Protocols: Set the data key only.
Please note that if you need to do a long running operation, then you will need to start a separate service (the service should present a notification in the notification area that it is running, otherwise you will get a crash on the newer Android versions)
Fixed by using AlarmManager. Schedule an alarm in 10 minutes, and when completing the code within the alarm, schedule a new alarm in 10 minutes.
AlarmManager can wake the phone if it is in doze mode, which means all code inside the trigger will be executed properly.
I am using blescan with scanfilters to detect beacons it's working very fine in foreground and background up to oreo version but when it comes to android pie it's not able to send pending broadcast in background.
ScanSettings settings = (new ScanSettings.Builder().setScanMode(ScanSettings.SCAN_MODE_LOW_POWER)).build();
final List<ScanFilter> scanFilters = new ArrayList<>();
scanFilters.add(getScanFilter());
BluetoothAdapter bluetoothAdapter;
final BluetoothManager bluetoothManager =
(BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
bluetoothAdapter = bluetoothManager.getAdapter();
Intent intent = new Intent(this.getApplicationContext(), MyBroadcastReceiver.class);
intent.putExtra("o-scan", true);
PendingIntent pendingIntent = PendingIntent.getBroadcast(this.getApplicationContext(), 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
bluetoothAdapter.getBluetoothLeScanner().startScan(scanFilters, settings, pendingIntent);
public class MyBroadcastReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
int bleCallbackType = intent.getIntExtra(BluetoothLeScanner.EXTRA_CALLBACK_TYPE, -1);
if (bleCallbackType != -1) {
Log.d(TAG, "Passive background scan callback type: "+bleCallbackType);
ArrayList<ScanResult> scanResults = intent.getParcelableArrayListExtra(
BluetoothLeScanner.EXTRA_LIST_SCAN_RESULT);
// Do something with your ScanResult list here.
// These contain the data of your matching BLE advertising packets
}
}
}
Android 9 introduces several behavior changes, such as limiting background apps' access to device sensors and Wi-Fi scans.
These changes affect all apps running on Android 9, regardless of target SDK version.
Sensors that use the continuous reporting mode, such as accelerometers and gyroscopes, don't receive events.
Android 9 Limited access to sensors in background:
Android 9 limits the ability for background apps to access user input and sensor data. If your app is running in the background on a device running Android 9, the system applies the following restrictions to your app:
Sensors that use the continuous reporting mode, such as accelerometers and gyroscopes, don't receive events.
Sensors that use the on-change or one-shot reporting modes don't receive events.
Solution:
If your app needs to detect sensor events on devices running Android 9 while the app is in the background, use a foreground service.
I an example test Android app using Oreo (API 26) and the the code above (slightly modified) to detect beacons. I am using the Pixel 3 XL (with Pie).
I think that the hard part about this is to know for sure if the code in onRecieve() in MyBroadcastReceiver is actually being run upon detection of a beacon when the device is running on battery only (disconnected from Android-studio and Logcat (USB)).
Using Volley (com.android.volley) to submit a HTTP request to a local http server, I was able to demonstrate that it works as documented - ie. I am able to receive the http request when beacon(s) are detected. However, Volley only sends these these requests when Android is awake or when it periodically wakes up and connects to the network - which in my simple tests was about every 15 minutes (plus some variation), but I did get all the beacon ScanResults on my HTTP server, just in delayed up to 15 minutes. I was even able to remove the app from the list of running apps (you know; swiping up to remove the app) and still see that the onRecieve() in MyBroadcastReceiver was receiving BLE ScanResults.
How do you know that the onRecieve() in MyBroadcastReceiver is being killed? I am very interested to know how you know this.
Hi i am running a background service using alaram manager its working fine but for some mi devices background service is not working.I used sevices but it is not working how to run my background service in mi ?
MI UI has its own security options, so what you need to is not just above mentioned sticky Service,
you need to
Enable Autostart
go to power setting make changes as per these youtube videos
https://www.youtube.com/watch?v=-Ffgir-QgsU, or refer for this for more suggestions
https://www.quora.com/How-do-I-keep-an-app-running-in-the-background-in-MIUI
then you have created a custom broadcast receiver which will start the service when your service is destroyed
as per this example https://fabcirablog.weebly.com/blog/creating-a-never-ending-background-service-in-android
If the 3rd option doesn't work onDestroy recall of the service call the custom broadcast receiver on
w
public void onTaskRemoved(Intent rootIntent) {
super.onTaskRemoved(rootIntent);
Log.e(TAG, " In recieve Custome Broadcast receiver");
Intent broadcastIntent = new Intent("ac.in.ActivityRecognition.RestartSensor");
sendBroadcast(broadcastIntent);
}
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.setComponent(new ComponentName("com.android.settings","com.android.settings.Settings$HighPowerApplicationsActivity"));
startActivity(intent);
try this code
it will open one setting page
then find your app and then tap "Don't Optimize"
it will turn off battery optimization and your background services run without problem
When you start a service by extending an Service class than you will get the call inside OnStartCommand() this method has three types of return type on the basis of this return type operating system itself manage when to start a service.
So suppose if your service gets killed in between due to low memory or any other issue when you return a correct type from onStartCommand() than os will take care of when to start service again.
Three return types are:
START_STICKY : When this is the return type than os takes the guarantee to restart the service again if its get killed it will definitely start you service again even if there is no pending intent it will start the service by passing intent as null.
START_NOT_STICKY: says that, after returning from onStartCreated(), if the process is killed with no remaining start commands to deliver, then the service will be stopped instead of restarted. This makes a lot more sense for services that are intended to only run while executing commands sent to them. For example, a service may be started every 15 minutes from an alarm to poll some network state. If it gets killed while doing that work, it would be best to just let it be stopped and get started the next time the alarm fires.
START_REDELIVER_INTENT is like START_NOT_STICKY, except if the service's process is killed before it calls stopSelf() for a given intent, that intent will be re-delivered to it until it completes (unless after some number of more tries it still can't complete, at which point the system gives up). This is useful for services that are receiving commands of work to do, and want to make sure they do eventually complete the work for each command sent.
I am having a problem where my service is being killed even though I am holding a wake lock and I have called startForeground. When this occurs the tablet (ASUS Transformer TF101), stops the service without calling onDestroy. There are no other apps visible, and log cat shows nothing out of the ordinary (no 'out of memory' message etc). Immediately after being killed, the service restarts.
The app I am developing is a chat client and needs a constant connection, it is also plugin based, so my app is developed as such: Client - HostService - Multiple child 'Services'.
The host service is sticky holds the wake lock and calls startForeground (and displays a notification as such), the child services are not sticky, do not hold wake locks and are background services.
If the client itself is open the issue does not occur, but the model I am going for is that the user can use the device and stay connected (receiving messages etc) without having the client itself open at all times.
Can anybody offer any explanation as to why the service is being killed in this way, and if so prevent it from happening? As the chat clients show when a user logs on and off, and the service dying kills all open connections, this makes the chat client 'bounce'. At present it seems to happen somewhere between every 15 and 45 minutes.
Also, if anybody is aware of a way to keep a socket connection open continuously without holding a wake lock for the entire connection duration, I would love to hear it!
The trimmed test case version of the host service source is below.
public class HostService extends Service
{
PowerManager m_powerManager = null;
PowerManager.WakeLock m_wakeLock = null;
#Override
public IBinder onBind( Intent intent )
{
return m_serviceImplementation;
}
#Override
public void onCreate()
{
super.onCreate();
}
#Override
public void onDestroy()
{
if( m_wakeLock != null )
{
m_wakeLock.release();
m_wakeLock = null;
}
stopForeground( true );
super.onDestroy();
}
#Override
public int onStartCommand( Intent intent, int flags, int startId )
{
// Display a notification about us starting. We put an icon in the
// status bar.
Notification notification = createNotification();
startForeground( R.string.service_running, notification );
if( m_powerManager == null )
{
m_powerManager = (PowerManager)getSystemService(Context.POWER_SERVICE);
}
if( m_wakeLock == null )
{
m_wakeLock = m_powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "Keep background services running");
m_wakeLock.acquire();
}
// We want this service to continue running until it is explicitly
// stopped, so return sticky.
return START_STICKY;
}
/**
* Create a notification to show the service is running
*/
private Notification createNotification()
{
CharSequence text = getText( R.string.service_running );
CharSequence title = getText( R.string.app_name );
// The PendingIntent to launch our activity if the user selects this
// notification
PendingIntent contentIntent = PendingIntent.getActivity( this, 0, new Intent(this, MainChat.class) , 0 );
Notification notification = new Notification( android.R.drawable.sym_action_chat, title, System.currentTimeMillis() );
notification.setLatestEventInfo( this, title, text, contentIntent );
return notification;
}
private final IMessageInterface.Stub m_serviceImplementation = new IMessageInterface.Stub()
{
...
};
}
Android Manifest (relevant bits):
<uses-sdk android:minSdkVersion="11" android:targetSdkVersion="11" />
<service android:name="com.mydomain.chatClient.server.HostService" android:exported="true" android:enabled="true" android:process=":remote"/>
<uses-permission android:name="android.permission.WAKE_LOCK" />
I am having a problem where my service is being killed even though I am holding a wake lock and I have called startForeground.
startForeground() reduces the likelihood of a service being killed, but it does not prevent it.
The app I am developing is a chat client and needs a constant connection, it is also plugin based, so my app is developed as such: Client - HostService - Multiple child 'Services'.
I recommend getting rid of one of those layers. Even if the OS doesn't shut you down, many users will (e.g., task killer, Running Services in Settings), considering you to be running too many services.
If the client itself is open the issue does not occur, but the model I am going for is that the user can use the device and stay connected (receiving messages etc) without having the client itself open at all times.
I recommend making that optional. You may think it's sexy. Some of your users will attack you for wasting their battery.
Can anybody offer any explanation as to why the service is being killed in this way, and if so prevent it from happening?
I'd start by getting rid of android:process=":remote". You don't need it. You don't want it. You may be hurting yourself by having it, as it may accelerate Android's interest in getting rid of your service. You absolutely are hurting users by having it, because you are wasting RAM for no good reason.
Then, I'd get rid of the plugins, if you implemented those as separate applications. In that case, each one of those will be running in its own process, wasting yet more RAM. Besides, your current implementation would be flawed, as you would be stuck having your service be named com.mydomain.chatClient.server.HostService until the end of time, since you didn't use an <intent-filter> to separate the concerns of "what the service is named internally" and "what the service is called by other separately-installed applications that wish to use it". And if you didn't implement the plugins as separate applications, then I fail to see the value in having them be in separate services, rather than folding them all into the one service.
Also, if anybody is aware of a way to keep a socket connection open continuously without holding a wake lock for the entire connection duration, I would love to hear it!
If the socket is on wireless data, instead of WiFi, you do not need a WakeLock all the time. The socket will remain open, and incoming packets on that socket will wake up your code. At that point, you'd want to grab a WakeLock long enough for you to do whatever you're doing with the data when it arrives, then release the WakeLock.
If you are on WiFi, though, this trick doesn't work, so a WakeLock (and probably a WifiLock) will be required.