title: How and on what condidtions are FCM high-priority messages de-prioritized? How to fetch cached FCM messages from server?
body: <p>According to <a href="https://firebase.google.com/docs/cloud-messaging/concept-options#setting-the-priority-of-a-message" rel="noreferrer">FCM documentation</a> high-priority messages might become de-prioritized, if the FCM server detects a pattern in which high-priority messages do not result into user interactions. The details of this mechanism are left unspecified. Questions:</p>
  
  <ul>
  <li>How exactly does this work?</li>
  <li>How does the detection algorithm gathers the data?</li>
  <li>For how long are messages de-prioritized?</li>
  </ul>
  
  <p>Secondly, the Android app has a method that checks how old the most recently received message is. This methods sometimes reports wrong results, if messages with normal priority have not been delivered yet but are still cached at the FCM server. Question:</p>
  
  <ul>
  <li>How can make the Android app to fetch all messages first?</li>
  </ul>
  
  <p><em>Some optional background information:</em></p>
  
  <p>I am writing a monitoring app for some safety critical application. The on-premise server can be in one out of two mutually exclusive states: "idle" or "alarm". The state is sent via FCM to all registered clients. To ensure that the server is still running, the state is periodically broadcasted as a heartbeat. These heartbeat messages are sent with normal priority. Moreover, whenever the state changes from "idle" to "alarm" an additional, offbeat message with high priority is sent immediately. E.g. the sequence of messages is something like</p>
  
  <pre><code>...  idle  idle  idle  *alarm*  alarm  alarm  alarm  idle  idle  ...
  </code></pre>
  
  <p>As the first alarm message in a row triggers a notification and all other messages have only normal priority, there is (hopefully) no risk of being de-prioritized by FCM.</p>
  
  <p>The Android app incorporates a <code>PeriodicWorkRequest</code> that serves as a watchdog and checks if the heartbeat is still coming in. If the most recently received message is too old (older than 30mins), a "Connection lost" notification is displayed to the user to warn him.</p>
  
  <p>Here is the problem:</p>
  
  <p>The usual heartbeat messages have normal priority and are cached at the FCM server. The watchdog raises a false "connection lost" notification. The device is woken up (due to the notification) and suddenly the most recent heartbeat message comes in (they are collapsed at the server).</p>
  
  <p>I see two solutions (or workarounds):</p>
  
  <ul>
  <li><p>Make all messages high-priority messages, so that they are delivered immediately and the watchdog always sees the most recent message. However, I fear that the FCM de-prioritization algorithm kicks in. (99,95% are boring "idle" messages) </p></li>
  <li><p>Before the watchdog checks the time of the latest message and eventually raises a warning, I have to ensure programmatically that all messages have been fetched.</p></li>
  </ul>
  
  <p><em>Side note:</em></p>
  
  <p>I totally understand why Google is enforcing more and more restrictions on background executions and asynchronous tasks. (Broadcast receivers have become more or less useless, AlarmManager has been restricted, JobScheduler can be deferred and Android 9 introduces the concept of "standby buckets".) Many developers have abused these APIs to do insane things for which a better (battery-friendly) solution would have existed. However, all these restrictions make it a very hard job to implement a safety-critical application that is governed by legal regulations, that must provide reliability guarantees and therefore requires line-monitoring of an unreliable network.</p>
  
  <p>All the power management mechanism do not seem to consider safety-related scenarios. The user has no intent to use the app (which is perfectly fine) and no news are good news in this particular case. I.e. the app simply stays in the background. Unfortunately, the app is categorized into the standby bucket for "rare" apps and the app gets penalized which is not good.</p>