Our app is crashing on Android O due to the new background execution limits. We are on Firebase version 10.2.1, which is the one that added Android O support.
Seems like an issue with Firebase? Or is there some change needed to support this on our end?
java.lang.IllegalStateException: Not allowed to start service Intent { act=com.google.firebase.INSTANCE_ID_EVENT pkg=my.package.name cmp=my.package.name/my.package.name.MyFcmIdService (has extras) }: app is in background uid UidRecord{30558fa u0a327 RCVR idle procs:1 seq(0,0,0)}
at android.app.ContextImpl.startServiceCommon(ContextImpl.java:1505)
at android.app.ContextImpl.startService(ContextImpl.java:1461)
at android.content.ContextWrapper.startService(ContextWrapper.java:644)
at android.support.v4.content.WakefulBroadcastReceiver.startWakefulService(WakefulBroadcastReceiver.java:99)
at com.google.firebase.iid.zzg.b(zzg.java:9)
at com.google.firebase.iid.zzg.a(zzg.java:72)
at com.google.firebase.iid.zzg.a(zzg.java:2)
at com.google.firebase.iid.FirebaseInstanceIdService.a(FirebaseInstanceIdService.java:23)
at com.google.firebase.iid.FirebaseInstanceIdService.a(FirebaseInstanceIdService.java:34)
at com.google.firebase.iid.FirebaseInstanceId.<init>(FirebaseInstanceId.java:31)
at com.google.firebase.iid.FirebaseInstanceId.getInstance(FirebaseInstanceId.java:47)
at com.google.firebase.iid.FirebaseInstanceId.a(FirebaseInstanceId.java:4)
at com.google.firebase.iid.FirebaseInstanceIdService.a(FirebaseInstanceIdService.java:19)
at com.google.firebase.iid.FirebaseInstanceIdService.b(FirebaseInstanceIdService.java:35)
at com.google.firebase.iid.zzb$zza$1.run(zzb.java:24)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636)
at java.lang.Thread.run(Thread.java:764)
Update Upgrading to 11.4.2 resolves this issue.
#KaMyLL is right. I had the same issue with our app and could solve it by replacing the IntentService (which we have started within onTokenRefresh()) with an JobIntentService.
Because I found the JobScheduler and JobIntentService docs a bit confusing, I would like to some everything up with some code snippets. I hope this makes everything clear to everyone having this issue.
What is causing this issue?
Due to the new Background Execution Limits of Android 8, you should not start background services anymore when the app could be in background:
While an app is in the foreground, it can create and run both foreground and background services freely. When an app goes into the background, it has a window of several minutes in which it is still allowed to create and use services. At the end of that window, the app is considered to be idle. At this time, the system stops the app's background services, just as if the app had called the services' Service.stopSelf() methods.
And also:
In many cases, your app can replace background services with JobScheduler jobs.
So for Android 7.x and below, using startService() when the app is in background is (as far as I know) no problem. But in Android 8, this results in a crash. In consequence, you should use a JobScheduler now. The behavioral difference between JobScheduler and an IntentService is that an IntentService is executed immediately. On the other hand, a job enqueued to a JobScheduler is not guaranteed to be executed immediately. The Android OS will determine when there is a good point of time to do so in order to be more energy efficient. So there might be a delay. And I have no idea so far how long this could take.
So one solution could be to check the OS version and branch your code using if-else. Fortunately, the support library helps us to solve this in a more elegant way without duplicating any code: JobIntentService, which basically does this for you under the hood.
How to reproduce the issue?
The first quote above states that the app still "has a window of several minutes in which it is still allowed to create and use services.", so in order to reproduce and debug the issue (with the example of onTokenRefresh() in Firebase), you could set a breakpoint before your start your service with startService(). Close the app and wait there for 5-10 minutes. Continue the execution and you will see the IllegalStateException from this question.
Being able to reproduce the issue as fundamental to make sure that our fixes really solve the problem.
How to migrate my IntenService to JobIntentService?
I use FirebaseInstanceIdService.onTokenRefresh() as an example:
a) Add the BIND_JOB_SERVICE permission to your service:
<service android:name=".fcm.FcmRegistrationJobIntentService"
android:exported="false"
android:permission="android.permission.BIND_JOB_SERVICE"/>
b) Instead of extending from IntentService, simply extend from android.support.v4.app.JobIntentService, rename the onHandleIntent(Intent) method to onHandleWork(Intent), and add a enqueueWork(Context, Intent) convenient function:
public class FcmRegistrationJobIntentService extends JobIntentService
{
// Unique job ID for this service.
static final int JOB_ID = 42;
// Convenience method for enqueuing work in to this service.
public static void enqueueWork(Context context, Intent work) {
enqueueWork(context, FcmRegistrationJobIntentService.class, JOB_ID, work);
}
#Override
protected void onHandleWork(#NonNull Intent intent) {
// the code from IntentService.onHandleIntent() ...
}
}
c) Start the job using the enqueueWork() convenient function:
public class ComfyFirebaseInstanceIdService extends FirebaseInstanceIdService {
#Override
public void onTokenRefresh() {
Intent intent = new Intent(this, FcmRegistrationJobIntentService.class);
// startService(intent);
FcmRegistrationJobIntentService.enqueueWork(this, intent);
}
}
I hope this example is helpful. At least after following these steps, I was not able to reproduce the issue on my Android 8 device anymore, and it continues to work an my Android 7 device.
Update
as FirebaseInstanceIdService deprecated we should remove this from the code, and use onNewToken from FirebaseMessagingService instead.
I've done some research about it and the best option is to transform IntentService into JobIntentService available in app compat library. It would behave like IntentService on all pre-Oreo devices. On Android 8 and above it will enqueue job to android system JobScheduler. This job by default have set deadline parameter to 0, so theoretically it should fire as fast as possible.
as of today (26/10/2018), FirebaseInstanceIDServie isdeprecated, try this to fix the above issue link
Related
My hybrid Cordova Android app uses one custom plugin in which I do a great deal of background work at intervals of ca 30 minutes. Up until now I have been using AlarmManger with a setInexact alarm to perform the work. The only real issue I have with that route is that the alarm does not survive a reboot. Given that I am now only supporting Android 6 (API 23)+ devices I am now experimenting with replacing AlarmManager with JobScheduler. My efforts thus far are shown below
public class UnyService extends JobService
{
#Override
public boolean onStartJob(JobParameters params)
{
UnyHandler.sendMessage(Message.obtain(UnyHandler,1,params));
return true;
}
#Override
public boolean onStopJob(JobParameters params)
{
UnyHandler.removeMessages(1);
return false;
}
where I am using a Handler to perform the actual work. The code for Handler is shown below
private Handler UnyHandler = new Handler(new Handler.Callback()
{
#Override
public boolean handleMessage(Message msg)
{
Feedback.postBackInfo("Handled it!");
jobFinished((JobParameters)msg.obj,false);
return true;
}
});
I then use the following code to get the job up and running
private void launchTimerJob()
{
timerJob =
(JobScheduler)context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
JobInfo.Builder builder = new JobInfo.Builder(1,new
ComponentName(Utils.packName,UnyService.class.getName()));
builder.setPeriodic(30000);
builder.setPersisted(true);
builder.setBackoffCriteria(30000,JobInfo.BACKOFF_POLICY_LINEAR);
if (0 >= timerJob.schedule(builder.build()))
Feedback.postBackInfo("Job Build Error");
else Feedback.postBackInfo("Job Created and Scheduled");
}
where Feedback and Utils are other classes in my app which provide support services. To facilitate testing I am using a relatively small period of 30 seconds.
When I install and start the app the plugin init code calls launchTimerJob() and I get the "Job Created and Scheduled" notification back as expected.
From that point forward I had expected to get Handled It! notifications from Handler above at intervals of roughly 30s. A notification has turned up on the odd occasion but a totally arbitrary time measuring from App startup and has not obliged by repeating. Clearly, I am doing something wrong here.
Android docs could do a better job of mentioning that the minimum interval allowed for periodic jobs is 900,000 milliseconds, i.e.
15 minutes !!!!
I gather that prior to API 24 (Nogat) it was possible to use smaller intervals but no longer. Be wary of the various JobScheduler tutorials you will find out there. There are many that are quite dated and Android Jobs appears to be a still evolving API.
My own reason for originally using AlarmManager was to enable background tasks to be performed when the app was, well, backgrounded. However, with the coming of doze mode this strategy fails since the app will simply not get broadcast messages when the device is dozing.
Consider the following strategy instead
When the app is foregrounded you can quite simply use a Handler to manage periodic tasks - even those that happen at an interval of a few seconds.
No normal app should ever have to carry out background tasks at that frequency (every few seconds) when the phone is dozing - and when that is required there is a route via a specific request for the app to be exempted from battery optimizations. In such instances a periodic JobScheduler with a 15 minute period is the best you can do.
I'm trying to find the way to keep the database updated, but the method which does it consumes a lot of time so I try to create a background task to do it.
I searched for solutions and I read this article of different options to run background processes: https://www.hanselman.com/blog/HowToRunBackgroundTasksInASPNET.aspx
But I don't know what's is the best solution out of those, like I'm trying to execute it outside the application. I found something about creating a Windows Service too, but I don't know how, I didn't manage to find some good examples.
What is the best way to keep my database updated everytime I access the application without losing the time it consumes? If you can help me to see the light I would appreciate that so much.
I'm really happy with FluentScheduler, which is handling all my mission-critical scheduling. As well as firing jobs on a scheduled basis, it can also do them on demand, like so:
// Define your job in its own class
public abstract class MyJob : IJob
{
public void Execute()
{
// Do stuff here...
}
}
// Schedule your job at startup
var runAt = DateTime.Today.AddHours(1); // 1am
if (runAt<DateTime.Now)
runAt = runAt.AddDays(1);
Schedule<MyJob>()
.WithName("My Job Name") // Job name, required for manually triggering
.NonReentrant() // Only allow one instance to run at a time
.ToRunOnceAt(runAt) // First execution date/time
.AndEvery(1).Days().At(runAt.Hour, runAt.Minute); // Run every day at the same time
// To manually trigger your job
ScheduledJobRegistry.RunTaskAsync("My Job Name");
I have the scheduled jobs running in a windows Service and use SignalR as a means of triggering them remotely from an MVC Web App when required.
You can use an async method. Just use a void instead of Task.
public async void LongRunningMethod () {
...
// Insert long running code here
...
}
Then call it and it will execute in the background. Be aware that you can have hidden exceptions without proper were handling.
You can also use Hangfire which is a pretty awesome background task scheduler
Here is an example of using Hangfire to run a daily task
RecurringJob.AddOrUpdate(() => Console.Write("Easy!"), Cron.Daily);
To start, let me say that I have read several questions here about SingleInstance, but still cannot find a direct answer that helps me. That said, I apologize if I missed anything.
Here's my question:
I am building a Xamarin Forms app for iOS and Android. I have a single AppInitializer class in a PCL where I register all of my interface dependencies using Autofac. I then assign the Container from the builder as a static property on the app class. The problem I encounter is that while I'm registering everything with .SingleInstance(), I'm not actually getting a single instance.
Init Logic Example:
var builder = new ContainerBuilder();
builder.RegisterType<ErrorHandler>().SingleInstance().As<IErrorHandler>();
…
builder.RegisterType<MemberViewModel>().SingleInstance().As<IMemberViewModel>();
…
AppContainer.Current = builder.Build();
I am letting Autofac handle resolving interfaces in my constructors. For example:
public MemberViewModel(ISettingsViewModel settings, IErrorHandler errorHandler, …) : base(settings, errorHandler){…}
I then use said model on a page as below:
Example page usage:
public ProfilePage()
{
InitializeComponent();
var displayModel = Model.CurrentMember;
…
}
…
**public IMemberViewModel Model =>
AppContainer.Current.Resolve<IMemberViewModel>();**
In this example I set Model.CurrentMember's properties immediately before arriving on this page. I've set breakpoints and know for a fact this is happening. However, when I resolve the instance of the model, the properties on CurrentMember are null.
Am I doing something wrong here or have I encountered a bug?
-Edit-
Made it clear that I'm using Autofac.
-Edit 2-
Adding more detail.
My implementation of the IMemberViewModel class has various properties on it, including an observable object called current member. It is declared as below:
public class MemberViewModel : ViewModelBase, IMemberViewModel
{
…
(see constructor above)
…
public MemberDisplay CurrentMember =>
m_CurrentMember ?? (m_CurrentMember = new MemberDisplay())
On the implementation of IMemberViewModel I have a method that sets the various properties on CurrentMember.
The order of operations is this:
The end user taps an image for a member. This fires a command on the (theoretically) singleton instance of the IMemberViewModel implementation. This command executes an async task that awaits an async call to the API to load the data for that member. After that data is loaded and the properties set on CurrentMember, the app navigates to the profile screen. The profile screen resolves IMemberViewModel (per above).
Expected Behavior:
The properties on CurrentMember from the resolved instance of IMemberViewModel are set to the values that have just been set from the load data method. This expectation arises from assuming that there is a single instance of IMemberViewModel.
Actual Behavior:
The CurrentMember's properties are at their default values, i.e. string.Empty, 0, null, etc.
The odd thing here is that this doesn't happen to every model. I have a message model that I am resolving in the same manner on the same screen and it seems to be fine.
This issue turned out to be caused by the way we were going about initializing everything. For posterity's sake, I will give a brief breakdown of what was happening and what I did to prevent it.
Previous App Flow:
App opens & constructor is called. This calls into the initialization routine above.
User logs in.
First instance of IMemberViewModel resolved using static container.
A message pops up asking the user for Push Notifications Permissions
When this happens, the app OnSleep is called (iOS)
After the user selects an answer, OnResume is called.
OnResume calls initialization routine
New container created.
Call to load data happens on old container, new pages reference new container.
Issue arises as described above.
Correction to the flow:
First, from what I can tell the init calls do not need to be made on resume and/or start if made in the app constructor. If the app is "killed" because other apps need the memory space, a fresh version of the app will be created on next launch (see the Android Activity Lifecycle and the iOS App Lifecycle).
Second, because I'm paranoid and because it can't hurt, in the app init routine I am now checking to determine whether the container exists and whether the interface is already registered.
public static void Init(ISetup setup)
{
if (Container != null && IsModelRegistered()) return;
RegisterDependencies(setup);
…
}
private static bool IsModelRegistered()
{
return Container.IsRegistered<IMemberViewModel>();
}
I've been coding a simulation in Java and now generate graphs of the results in JavaFX. However, I'm stumped as to how to call the graphs so that when I try to run the simulation (and generate the graphs) for a second time, I don't get the "can't call launch() more than once" error. I read that launch() can only be called once, so what do I need to change to call the graphs successfully on a second run of the simulation?
public class AnswerWorker extends SwingWorker<Void, Integer> {
protected Void doInBackground() throws Exception
{
AMEC.runsimulation();
return null;
}
protected void done()
{
try {
Graphs.launch(Graphs.class, "");
JOptionPane.showMessageDialog(InputGUI.this, AMEC.unsuccesfulpercentage + "% of iterations had trucks that had to sleep over");
AMEC.unsuccesfulpercentage = 0;
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
with a pretty standard graphing class:
public class Graphs extends Application {
#Override public void start(Stage stage) {
....
stage.show();
}
}
Why are you using SwingWorker in a JavaFX application? If your graphs are computed for display in a JavaFX application, there is no reason for you to use the Event Dispatch Thread (AWT). If I'm not mistaken, With the release of JDK 8, the JavaFX Application Thread and the Event Dispatch Thread will become one, so there is no reason (yet) for you to use SwingWorker. If I really am wrong, still, there is no reason for you to use SwingWorker. Although it is possible the coupling of Swing components in JavaFX applications, you should only use EDT when manipulating Swing components, not JavaFX nodes. The following link says this:
...The JavaFX application thread is a different thread from the Swing and AWT Event Dispatch Thread (EDT), so care must be taken when embedding JavaFX code into Swing applications...
Source: http://docs.oracle.com/javafx/2/architecture/jfxpub-architecture.htm
To learn how you can put processes to be done in the background, and also find out which thread is responsible for handling the JavaFX elements, check out this link:
http://docs.oracle.com/javafx/2/threads/jfxpub-threads.htm
Regarding your question, I believe the beginning of a JavaFX application should be called only once. So much is, that when a JavaFX application is started, the thread of main method is captured, and is only returned when the JavaFX application is finalized. Just see the Application DOC (Especially this part). Note also that the life cycle of a JavaFX application is given by the following steps:
Life-cycle
The entry point for JavaFX applications is the Application class. The JavaFX runtime does the following, in order, whenever an application is launched:
Constructs an instance of the specified Application class
Calls the init() method
Calls the start(javafx.stage.Stage) method
Waits for the application to finish, which happens when either of
the following occur:
the application calls Platform.exit()
the last window has been closed and the implicitExit attribute on Platform is true
Calls the stop() method
You might be using the wrong approach. I believe that you should leave your JavaFX application running while you're processing something. Once you have processed what you want in the background, you should make your JavaFX application show the results. The way your JavaFX application run while something is being processed in the background is entirely up to you. Maybe you should hide the window while something is processed, and display it again with your chart done. As I said, this is something you will have to decide. I recommend you to take a look at the documentation of classes referring to the window system, starting with Window, and then Stage.
Any questions, we're here. Good Luck! :)
EDIT:
From what I'm seeing, the user jewelsea is right. Apparently it is not certain that the EDT and the JavaFX Application Thread shall become one (it would be quite interesting if that happened). But anyway, be careful not to confuse yourself with the use of both threads.
i am using Quartz.NET in my ASP.NET web application. i put the following code in a button click handler to make sure that it executes (for testing purposes):
Quartz.ISchedulerFactory factory = new Quartz.Impl.StdSchedulerFactory();
Quartz.IScheduler scheduler = factory.GetScheduler();
Quartz.JobDetail job = new Quartz.JobDetail("job", null, typeof(BackupJob));
Quartz.Trigger trigger = Quartz.TriggerUtils.MakeDailyTrigger(8, 30); // i edit this each time before compilation (for testing purposes)
trigger.StartTimeUtc = Quartz.TriggerUtils.GetEvenSecondDate(DateTime.UtcNow);
trigger.Name = "trigger";
scheduler.ScheduleJob(job, trigger);
scheduler.Start();
here's "BackupJob":
public class BackupJob : IJob
{
public BackupJob()
{
}
public void Execute(JobExecutionContext context)
{
NSG.BackupJobStart();
}
}
my question: why is "BackupJobStart()" not firing? i've used similar code before and it worked fine.
EDIT: #Andy White, i would have it in Application_Start in Global.asax. this doesn't work which is why i moved it to a button click handler to narrow down the problem.
Do you have the Quartz.NET logging hooked up? I once had a problem with a job not executing (I forget why), but once I got the Quartz.NET logging going, the problem was obvious.
It's worth a try (if you're not already doing it):
https://www.quartz-scheduler.net/documentation/quartz-2.x/quick-start.html
http://netcommon.sourceforge.net/
http://netcommon.sourceforge.net/documentation.html
Update: Simply add this to your program.cs to enable console logging:
Common.Logging.LogManager.Adapter = new Common.Logging.Simple.ConsoleOutLoggerFactoryAdapter { Level = Common.Logging.LogLevel.Info};
Maybe it's a problem of time.
I've had the same problem as you, and I live in a country which time is UTC + 2. So, when I set the StartTimeUtc to the trigger, I used DateTime.Now, so the trigger didn't have to fire until two hours later, and I thought it has to be fired in the very moment my code started.
Look carefully the time of the trigger's execution and its StartTime
Another possibility is the way you're running the scheduler. I'm not totally sure, but you may run into problems trying to run a scheduling threads in an ASP.NET application. Putting the SchedulerFactory/Scheduler objects in a button click handler doesn't seem like it would give you the desired results.
You may need to create the scheduler at a more "global" level, so that it can run in the "background" of the application. It might also make sense to move any scheduled work into a separate windows service, so that you don't have to maintain the scheduler in the web app.
When you had success in the past, how were you invoking the scheduler?
In my case, there was an issue with IoC - there were some Interfaces that weren't implemented. I could see what was wrong with mine by adding logging:
Common.Logging.LogManager.Adapter = new Common.Logging.Simple.ConsoleOutLoggerFactoryAdapter { Level = Common.Logging.LogLevel.Info};
to Program.cs as suggested by Andy White