firebase / quickstart-android

Firebase Quickstart Samples for Android
https://firebase.google.com
Apache License 2.0
8.86k stars 7.32k forks source link

Data only messages queued when device is idle (Doze mode?) even when priority is high and ttl=0 #100

Closed codevalley closed 8 years ago

codevalley commented 8 years ago

My environment

I tried executing the sample code. And to send downstream FCM, I have used GAE and have sent a message with following fields.

{
  "to": "...".
  "priority": "high",
  "delay_while_idle":false,
  "data": {...}
  "time_to_live": 0
}

I am not able to receive the message, until I unlock the phone (bring it out of idle state). In this process, it is ignoring two parameters set when sending the message

I combed through available documentations for FCM delivery, and they only explicitly mention behaviours for FCM with "notification" tag, FCM with "notification" and "data" tag. They don't clearly callout the behaviour when there is only "data" tag.

It feels like the message is getting delivered according to the params, but it is sent to the listener only on device wake up. Can this be the case? Because the POST response returns success and message_id instantenously.

PS: I believe this issue is fundamentally different from Issue #89 which was because the app was getting killed.

Steps to reproduce:

  1. Run the sample.
  2. Press home key and minimize the app (or leave it in foreground).
  3. Send device to idle with the following commands.
$ adb shell dumpsys battery unplug
$ adb shell dumpsys deviceidle step
  1. Send notification with above mentioned structure.

    Results.

    The message does not get delivered to the MyFirebaseMessagingService instance. Leave the phone in idle for indefinite time and unlock the phone. The message gets delivered immediately.

    Expected Results:

Message should get delivered immediately (priority: high) or it should be discarded on unsuccessful delivery (ttl:0)

2ndGAB commented 8 years ago

You are right this behavior is not clearly explained and I have my little idea about it... Are you sure your issue is fondamentally different from https://github.com/firebase/quickstart-android/issues/89?
Why do you say that? Are you sure you app is not Force Stopped when you put it in background?

First check if your device receives the message. Have a look at the logcat view and see if you receive such kind of messages:

mm-dd hh:ii:ss.nnn 1461-1461/? W/GCM-DMM: broadcast intent callback: result=CANCELLED forIntent { act=com.google.android.c2dm.intent.RECEIVE flg=0x10000000 pkg=com.your.package (has extras) } If no, maybe you don't ue the right token.

If yes, please tell us what Android Studio version do you use.

codevalley commented 8 years ago

@2ndGAB After scouring the internet I am relieved to atlast find someone interested in this issue, and actively being investigated. That aside, I am pretty sure my app is alive, (see steps to reproduce). This happens specifically in doze mode AFAIK. In fact, I don't think an app has to be alive for it to trigger onMessageReceived, since it has com.google.firebase.MESSAGING_EVENT intent-filter in Manifest. The messaging service will be initiated on a new message. But, when you force close an app, Android as a precaution does not start its services again, until user explicitly opens the app. This is to make sure some malicious/malfunctioning app does not go into a crash loop through its service. In my case, though, I don't force close the app, in fact, I don't even have to minimize the app. I leave the app on foreground. Just get phone go to doze mode. Everything stops there.

mm-dd hh:ii:ss.nnn 1461-1461/? W/GCM-DMM: broadcast intent callback: result=CANCELLED forIntent { act=com.google.android.c2dm.intent.RECEIVE flg=0x10000000 pkg=com.your.package (has extras) } If no, maybe you don't ue the right token.

Just tested this after seeing your comment. I don't get anything similar to the above mentioned log, in both cases (when I receive the message, when I don't).

I have never missed a downstream message, just that the delivery is gettin deffered if the phone is idle.

I use both Android Studio 2.1.2 and 2.2.6 both with Instant Run disabled.

2ndGAB commented 8 years ago

@codevalley According to my tests, the mentioned message is not always displayed on all devices.
I'm not sure about the state of the application when it's left in foreground but the phone in doze mode.

Anyway does your message fire onMessageReceive() when the application is in background?

I tried to execute adb commands you mentioned. I don't know what it's supposed to change on the device but it doesn't change anything visually. The second command replies by:

Stepped to: ACTIVE

Is it correct?

In that situation, the message fires onMessageReceive()

codevalley commented 8 years ago

@2ndGAB No. That's the whole problem. All I want is to get onMessageReceive().

2ndGAB commented 8 years ago

So, maybe I could propose you to install Android Studio 1.5 beside your 2.1.2 version, and try to build you project from 1.5 without changing anything and see....

codevalley commented 8 years ago

@2ndGAB it worked for you?

2ndGAB commented 8 years ago

@codevalley perfectly as strange as it appears. I made lot of tests exposed here

kroikie commented 8 years ago

@codevalley I assume you are calling adb shell dumpsys deviceidle step till the device is Stepped to: IDLE. In that case the device should receive the data message when priority is high and the message should never be delivered when priority is normal and ttl is 0.

It seems that your time_to_live, delay_while_idle and priority fields are being ignored, assuming that you left them out, what you are seeing would be expected. So looks like for some reason either these fields are not being sent to FCM or when they get to FCM they are being ignored. Could you add your GAE code that you are using to send the request to FCM?

codevalley commented 8 years ago

@kroikie I haven't left those params out. This is my GAE function to send a message (downstream).

    public void messageUser(String token, String dataJson) {
        try {
            String json = "{\n" +
                    "  \"to\": \""+ token + "\",\n" +
                    "  \"priority\": \"high\",\n" +
                    "  \"delay_while_idle\": false ,\n" +
                    "  \"data\": " + dataJson +
                    "  \"time_to_live\": 0 ,\n" +
                    "}";
            HttpClient httpClient = HttpClientBuilder.create().build();
            HttpPost post = new HttpPost(FCM_URL);
            post.addHeader("Content-Type", "application/json");
            post.addHeader("Authorization","Key="+SERVER_KEY);
            StringEntity postingString = new StringEntity(json);//gson.tojson() converts your pojo to json
            post.setEntity(postingString);

            HttpResponse resp = httpClient.execute(post);
            apiResponse = EntityUtils.toString(resp.getEntity());
        } catch (Exception e) {
            apiResponse = "Error " + e.toString();
        }
    }
kroikie commented 8 years ago

@codevalley thanks for the function, I wonder if your json is formatted the way you expect from the String. The json String that you are generating seems to be missing a comma after the dataJson String unless that string contains a comma itself. Could you possibly log the resulting json string and post it here?

codevalley commented 8 years ago

Ok. let me do it.

codevalley commented 8 years ago

@kroikie Here is the final json.

{
  "to": "c6NgGf6D.......vPNqHSN",
  "priority": "high",
  "delay_while_idle": false ,
  "time_to_live": 0 ,
  "data": {"buttons":7,"delay":0,"fromKey":"iS1ogJEI...i9Mxnz2","response":0,"timestamp":0,"toKey":"T1sg....Ea2"}
}

Sorry for the confusion around the 'comma', the running version has data in the end, I changed while tinkering around it see if something was wrong in the order. The json shown above is from actual GAE log.

kroikie commented 8 years ago

@codevalley the format of your request looks good, the data message should be delivered even if the device is in doze mode. Are you running into this issue while using this sample? Or are you using a different application.

I have run this sample on a Nexus 5X and I have not seen this issue. Also v9.4.0 was recently released could you update your dependencies to match those in this sample and try again. I'm especially curious about the results you are getting on the Nexus 5X.

codevalley commented 8 years ago

@kroikie This is weird. I upgraded to 9.4 and it is now working. I tested on 5x (Nougat preview), Nexus 5 (6.0.1) and Note 4 (6.0.1). Not sure how this got fixed, because I had upgraded to 9.4 yesterday and tested once after that, it didn't seem to work then. Anyways, I will test a little more today with this new build on different devices and confirm the fix and close this ticket. PS. Purely out of curiosity, would you mind testing this with v9.2.1 and see if you are able to reproduce this on that?

codevalley commented 8 years ago

@kroikie Did extensive testing yesterday. Here are the inferences.

Hence I can the issue is resolved (mostly). My doubt is if Doze/Idle are two different states? And when device is on doze, no FCM messages come through? It is almost like device is in hibernation?

kroikie commented 8 years ago

@codevalley I have tried the sample in doze mode using the adb commands and if I send a message with ttl 0 while the device is in doze mode (IDLE) it never receives the message, with both 9.2.1 and 9.4.0. Can you confirm that when you are using adb shell dumpsys deviceidle step that you are using it repeatedly till the response is Stepped to: IDLE?

Glad to hear that it seems to be working when the device is "really" in doze mode, but you should be able to simulate it with adb.

codevalley commented 8 years ago

@kroikie Actually it is not working when the device organically dozes (overnight).

So does it actually mean IDLE != DOZE ? Also, based on your own tests ( and not receiving messages), is it now confirmed that there is a delivery bug related to Doze in FCM?

kroikie commented 8 years ago

@codevalley to clarify:

If you are using high priority then you should expect to see the notifications coming in even when the phone is in IDLE/Doze, while IDLE and DOZE may not be the same thing FCM messages should be treated the same. ie Delivered if priority is high and not delivered otherwise.

It's difficult for me to define what you are seeing as a bug since I'm not able to reproduce it. It works as expected for me. If this issue persists what I would do is run your test cases and when you get the results you are seeing generate a bug report on the android device, along with the times and states the device was in and make a report to Firebase Support. Add my name to the report (Arthur Thompson) and I will pick it up and dig deeper to help resolve your issue.

I think however it is beyond the scope of this sample so I'm going to close this issue.

codevalley commented 8 years ago

@kroikie No problem. Just to clarify though,

if I send a message with ttl 0 while the device is in doze mode (IDLE) it never receives the message, with both 9.2.1 and 9.4.0.

does that mean you could reproduce the bug?

kroikie commented 8 years ago

@codevalley no it means that I was not able to reproduce the bug. If device is in doze mode (IDLE) then:

This is what I am seeing on both 9.2.1 and 9.4.0

coffeeforyou commented 7 years ago

Maybe this helps: https://developer.android.com/training/monitoring-device-state/doze-standby.html#understand_doze

I found it a great explanation of delivery behaviour for both Doze and App Standby.

KhaledJU commented 4 years ago

@codevalley hello from future :D I currently have exactly the same behavior you had... where you able to solve the issue? If you remember could you provide the conclusion, please?

kishan3390 commented 4 years ago

Hello @codevalley and @kroikie and @KhaledJU I am exactly in the same issue can you guys let me know the solution. This issue has eaten my precious time of almost a week . Please help