Home | History | Annotate | Download | only in gcm
      1 page.title=GCM Architectural Overview
      2 @jd:body
      3 
      4 <div id="qv-wrapper">
      5 <div id="qv">
      6 
      7 <h2>Quickview</h2>
      8 
      9 <ul>
     10 <li>Get an introduction to key GCM terms and concepts.</li>
     11 <li>Learn the basic features of a GCM application.</li>
     12 <li>Understand the role of the 3rd-party application server, and how to send messages and process results.</li>
     13 </ul>
     14 
     15 
     16 <h2>In this document</h2>
     17 
     18 <ol class="toc">
     19   <li><a href="#intro">Introduction</a> </li>
     20   <li><a href="#arch">Architectural Overview</a>
     21     <ol>
     22       <li><a href="#lifecycle">Lifecycle Flow</a></li>
     23       <li><a href="#user">What Does the User See?</a></li>
     24     </ol>
     25   </li>
     26   <li><a href="#writing_apps">Writing Android Applications that use GCM</a>
     27     <ol>
     28     <li><a href="#manifest">Creating the Manifest</a></li>
     29     <li><a href="#registering">Registering for GCM</a></li>
     30     <li><a href="#unregistering">Unregistering from GCM</a></li>
     31     <li><a href="#handling_intents">Handling Intents sent by GCM</a>
     32       <ol>
     33         <li><a href="#handling_reg">Handling Registration Results</a></li>
     34         <li><a href="#received_data">Handling Received Data</a></li>
     35       </ol>
     36     </li>
     37     <li><a href="#testing">Developing and Testing Your Android Applications</a></li>
     38     </ol>
     39   </li>
     40   <li><a href="#server">Role of  the 3rd-party Application Server</a>
     41     <ol class="toc">
     42       <li><a href="#send-msg">Sending Messages</a>
     43         <ol>
     44           <li><a href="#request">Request format</a></li>
     45           <li><a href="#response">Response format</a></li>
     46         </ol>
     47       </li>
     48     </ol>
     49     <li><a href="#stats">Viewing statistics</a>
     50   </li>
     51   <li><a href="#example">Examples</a></li>
     52 </ol>
     53 
     54 
     55 
     56 </div>
     57 </div>
     58 
     59 <p>Google Cloud Messaging for Android (GCM) is a free service that helps
     60 developers  send data from servers to their Android applications on  Android devices. This could be a lightweight message telling the Android application that there is new data to be fetched from the server (for instance, a movie uploaded by a friend), or it could be a message containing up to 4kb of payload data (so apps like instant messaging can consume the message directly). The GCM service handles all aspects  of queueing of
     61   messages and delivery to the target Android application running  on the target
     62   device.</p>
     63 <p class="note"> To jump right into using GCM with your Android
     64   applications, see the instructions in <a href="gs.html">Getting Started</a>.</p>
     65 
     66 
     67 
     68 
     69 <h2 id="intro">Introduction</h2>
     70 
     71 <p>Here are the primary characteristics of Google Cloud 
     72 Messaging (GCM):</p>
     73 
     74 <ul>
     75   <li>It allows 3rd-party application servers to send messages to
     76 their Android applications.</li>
     77   <li>GCM makes no guarantees about delivery or the order of messages.</li>
     78   <li>An Android application on an Android device doesn't need to be running to receive
     79 messages. The system will wake up the Android application via Intent broadcast when the  message arrives, as long as the application is set up with the proper
     80 broadcast receiver and permissions.</li>
     81   <li>It does not provide any  built-in user interface or other handling for
     82 message data. GCM  simply passes raw message data received straight to the
     83 Android application,  which has full control of how to handle it. For example, the
     84 application might post a notification, display a custom user interface, or 
     85 silently sync data.</li>
     86   <li>It requires devices running Android 2.2 or higher that also have the
     87 Google Play Store application installed, or or an emulator running Android 2.2 with Google APIs. However, you are not limited to deploying your
     88 Android applications through Google Play Store.</li>
     89   <li>It uses an existing connection for Google services. For pre-3.0 devices, this requires users to
     90 set up their Google account on their mobile devices. A Google account is not a requirement on devices running Android 4.0.4 or higher.</li>
     91 </ul>
     92 <h2 id="arch">Architectural Overview</h2>
     93 <p>This section gives an overview of how GCM works. </p>
     94 <p>This table summarizes the key terms and concepts involved in GCM. It is
     95 divided into these categories:</p>
     96 <ul>
     97   <li><strong>Components</strong> &mdash; The physical entities that play a role in
     98 GCM.</li>
     99   <li><strong>Credentials</strong> &mdash; The IDs and tokens that are used in
    100 different stages of GCM to ensure that all parties have been authenticated, and
    101 that the message is going to the correct place.</li>
    102 </ul>
    103 
    104 <table>
    105   <tr>
    106     <th colspan="2">Components</th>
    107   </tr>
    108   <tr>
    109     <td width="165"><strong>Mobile Device</strong></td>
    110     <td width="1176">The device that is running an Android application that uses
    111 GCM. This must be a 2.2 Android device that has Google Play Store installed, and it must
    112 have at least one logged in Google account if the device is running a version lower than Android 4.0.4. Alternatively, for testing you can use an emulator running Android 2.2 with Google APIs.</td>
    113   </tr>
    114   <tr>
    115     <td><strong>3rd-party Application Server</strong></td>
    116     <td>An application server that  developers  set up as part of implementing
    117 GCM in their applications. The 3rd-party application server sends data to an
    118 Android application on the device via the GCM server.</td>
    119   </tr>
    120   <tr>
    121     <td><strong>GCM Servers</strong></td>
    122     <td>The Google servers involved in taking messages from the 3rd-party
    123 application server and sending them to the device. </td>
    124   </tr>
    125   <tr>
    126     <th colspan="2"><strong>Credentials</strong></th>
    127   </tr>
    128   <tr>
    129     <td><strong>Sender ID</strong></td>
    130     <td>A project ID you acquire from the API console, as described in <a href="gs.html#create-proj">Getting Started</a>. The sender
    131 ID is used in the <a href="#registering">registration process</a> to identify an
    132 Android application that is permitted to send messages to the device.</td>
    133   </tr>
    134   <tr>
    135     <td><strong>Application ID</strong></td>
    136     <td>The Android application that is registering to receive messages. The Android application
    137 is identified by the package name from the <a href="#manifest">manifest</a>.
    138 This  ensures that the messages are targeted to the correct Android application.</td>
    139   </tr>
    140   <tr>
    141     <td><strong>Registration ID</strong></td>
    142     <td>An ID issued by the GCM servers to the Android application that allows
    143 it to receive messages. Once the Android application has the registration ID, it sends
    144 it to the 3rd-party application server, which uses it to identify each device 
    145 that has registered to receive messages for a given Android application. In other words,
    146 a registration ID is tied to a particular Android application running on a particular
    147 device.</td>
    148   </tr>
    149   <tr>
    150     <td><strong>Google User Account</strong></td>
    151     <td>For GCM to work, the mobile device must include at least one Google account if the device is running a version lower than Android 4.0.4.</td>
    152   </tr>
    153   <tr>
    154     <td><strong>Sender Auth Token</strong></td>
    155     <td>An API key that is saved on the 3rd-party application
    156 server that gives the application server authorized access to Google services.
    157 The API key is included in the header of POST requests  that send messages.</td>
    158   </tr>
    159 </table>
    160 
    161 <h3 id="lifecycle">Lifecycle Flow</h3>
    162 
    163 <p>Here are the primary processes involved in cloud-to-device messaging:</p>
    164 
    165 <ul>
    166   <li><a href="#register">Enabling GCM</a>. An Android application running on a
    167 mobile device registers to receive messages.</li>
    168   <li><a href="#push-process">Sending a message</a>. A 3rd-party application
    169 server sends messages to the device.</li>
    170   <li><a href="#receiving">Receiving a message</a>. An Android application
    171 receives a message from a GCM server.</li>
    172 </ul>
    173 
    174 <p>These processes are described in more detail below.</p>
    175 
    176 <h4 id="register">Enabling GCM</h4>
    177 
    178 <p>This is the sequence of events that occurs when an Android application
    179 running on a mobile device registers to receive messages:<span
    180 class="red-text"></span></p>
    181 
    182 <ol>
    183   <li>The first time the Android application needs to use the messaging service, it
    184 fires off a registration Intent to a GCM server. 
    185     <p>This registration Intent
    186 (<code>com.google.android.c2dm.intent.REGISTER</code>) includes the sender ID, and the Android application ID.</p>
    187 <p class="note"><strong>Note:</strong> Because there is no lifecycle method that is called when the application is run for
    188 the first time, the registration intent should be sent on <code>onCreate()</code>, but only if the application is not registered yet.
    189 </p>
    190   </li>
    191   <li>If the registration is successful, the GCM server broadcasts a <code>com.google.android.c2dm.intent.REGISTRATION</code> intent which gives the Android application  a registration
    192 ID. 
    193     <p>The Android application should store this ID for later use (for instance, to check on <code>onCreate()</code> if it is already registered). 
    194 Note that Google may periodically refresh the registration ID, so you should design your Android application
    195 with the understanding that the <code>com.google.android.c2dm.intent.REGISTRATION</code> intent may be called
    196 multiple times. Your Android application needs to be able to respond
    197 accordingly.</p></li>
    198   <li>To complete the registration, the Android application sends the registration ID to
    199 the application server. The application server typically stores the registration
    200 ID in a database. </li>
    201 </ol>
    202 
    203 <p>The registration ID lasts until the Android application explicitly unregisters
    204 itself, or until Google refreshes the registration ID for your Android application.</p>
    205 
    206 <p class="note"><strong>Note:</strong> When users uninstall an application, it is not automatically unregistered on GCM. It is only  unregistered when the GCM server tries to send a message to the device and the device answers that the application is uninstalled or it does not have a broadcast receiver configured to receive <code>com.google.android.c2dm.intent.RECEIVE</code> intents. At that point, you server should mark the device as unregistered (the server will receive a <code><a href="#unreg_device">NotRegistered</a></code> error).
    207   <p>
    208 Note that it might take a few minutes for the registration ID to be completed removed from the GCM server. So if the 3rd party server sends a message during this time, it will get a valid message ID, even though the message will not be delivered to the device.</p>
    209 </p>
    210 
    211 <h4 id="push-process">Sending a Message</h4>
    212 
    213 <p>For an application server to send a  message to an Android application, the following things must be in
    214 place:</p>
    215 
    216 <ul>
    217   <li>The Android application has a registration ID that allows it to receive messages
    218 for a particular device.</li>
    219   <li>The 3rd-party application server has stored the registration ID.</li>
    220 
    221 
    222 
    223 <li>An API key. This is something that the developer must have already
    224 set up on the application server for the Android application (for more discussion, see
    225 <a href="#server">Role of the 3rd-party Application Server</a>). Now it will
    226 get used to send messages to the device. </li>
    227 </ul>
    228 
    229 <p>Here is the sequence of events that occurs when the application server sends a 
    230 message:</p>
    231 
    232 <ol>
    233   <li>The application server sends a  message to  GCM servers.</li>
    234   <li>Google enqueues and stores the message in case the device is
    235 offline.</li>
    236   <li>When the device is online, Google sends the message to the device. </li>
    237   <li>On the device, the system  broadcasts the  message to the specified
    238 Android application via Intent broadcast with proper permissions, so that only the
    239 targeted Android application gets the message. This wakes the Android application up. The
    240 Android application does not need to be running beforehand to receive the message.</li>
    241   <li>The Android application processes the message. If the Android application is doing
    242 non-trivial processing, you may want to grab a {@link android.os.PowerManager.WakeLock} and do any processing in a Service.</li>
    243 </ol>
    244 
    245 <p> An Android application can  unregister GCM if it no longer wants to receive 
    246 messages.</p>
    247 
    248 <h4 id="receiving">Receiving a Message</h4>
    249 
    250 <p>This is the sequence of events that occurs when an Android application
    251 installed on a mobile device receives a message:</p>
    252 
    253 <ol>
    254   <li>The system receives the incoming message and extracts the raw key/value
    255 pairs from the message payload, if any.</li>
    256   <li>The system passes the key/value pairs to the targeted Android application
    257 in a <code>com.google.android.c2dm.intent.RECEIVE</code> Intent as a set of
    258 extras.</li>
    259   <li>The Android application extracts the raw data
    260 from the <code>com.google.android.c2dm.intent.RECEIVE</code><code> </code>Intent by key and processes the data.</li>
    261 </ol>
    262 
    263 <h3 id="user">What Does the User See?</h3>
    264 
    265 <p>When mobile device users install Android applications that include GCM, the Google Play Store will inform them that the Android application
    266 includes GCM. They must approve the use of this feature to install the
    267 Android application. </p>
    268 
    269 <h2 id="writing_apps">Writing Android Applications that Use GCM</h2>
    270 
    271 <p>To write Android applications that use GCM, you must have an application
    272 server that can perform the tasks described in <a href="#server">Role of the
    273 3rd-party Application Server</a>. This section describes the steps you take to
    274 create a client application that uses GCM.</p>
    275 
    276 <p>Remember that there is no user interface associated with  GCM.
    277 However you choose to process messages in your Android application is up to you.</p>
    278 
    279 <p>There are two primary steps involved in writing a client Android application:</p>
    280 
    281 <ul>
    282   <li>Creating a manifest that contains the permissions the Android application needs to
    283 use GCM.</li>
    284   <li>Implementing your  code. To use GCM, this implementation must
    285 include:
    286     <ul>
    287       <li>Code to start and stop the registration service.</li>
    288       <li>Receivers for the <code>com.google.android.c2dm.intent.RECEIVE</code> and <code>com.google.android.c2dm.intent.REGISTRATION</code> intents.</li>
    289     </ul>
    290   </li>
    291 </ul>
    292 
    293 <h3 id="manifest">Creating the Manifest</h3>
    294 
    295 <p>Every Android application must have an <code>AndroidManifest.xml</code> file (with
    296 precisely that name) in its root directory. The manifest presents essential
    297 information about the Android application to the Android system, information the
    298 system must have before it can run any of the Android application's code (for more
    299 discussion of the manifest file, see the <a href="{@docRoot}guide/topics/manifest/manifest-intro.html">Android Developers Guide</a>. To use the GCM feature, the
    300 manifest must include the following:</p>
    301 
    302 <ul>
    303   <li>The <code>com.google.android.c2dm.permission.RECEIVE</code> permission so the Android application can register and receive messages.</li>
    304   <li>The <code>android.permission.INTERNET</code> permission so the Android application can send the registration ID to the 3rd party server.</li>
    305   <li>The <code>android.permission.GET_ACCOUNTS</code> permission as GCM requires a Google account (necessary only if if the device is running a version lower than Android 4.0.4)</li>
    306   <li>The <code>android.permission.WAKE_LOCK</code> permission so the application can keep the processor from sleeping when a message is received.</li>
    307   <li>An <code>applicationPackage + &quot;.permission.C2D_MESSAGE</code> permission to prevent other Android applications from registering and receiving the Android application's
    308 messages. The permission name must exactly match this pattern&mdash;otherwise the Android application will not receive the messages.</li>
    309   <li>A receiver for <code>com.google.android.c2dm.intent.RECEIVE</code> and <code>com.google.android.c2dm.intent.REGISTRATION</code>, with the category set
    310 as <code>applicationPackage</code>. The receiver should require the <code>com.google.android.c2dm.SEND</code> permission, so that only the GCM
    311 Framework can send a message to it. Note that both registration and the receiving
    312 of messages are implemented as <a href="{@docRoot}guide/components/intents-filters.html">Intents</a>.</li>
    313   <li>An intent service to handle the intents received by the broadcast receiver.</li>
    314   <li>If the GCM feature is critical to the Android application's function, be sure to
    315 set <code>android:minSdkVersion=&quot;8&quot;</code> in the manifest. This
    316 ensures that the Android application cannot be installed in an environment in which it
    317 could not run properly. </li>
    318 </ul>
    319 
    320 <p>Here are excerpts from a manifest that supports GCM:</p>
    321 
    322 <pre class="prettyprint pretty-xml">
    323 &lt;manifest package="com.example.gcm" ...&gt;
    324 
    325     &lt;uses-sdk android:minSdkVersion="8" android:targetSdkVersion="16"/&gt;
    326     &lt;uses-permission android:name="android.permission.INTERNET" /&gt;
    327     &lt;uses-permission android:name="android.permission.GET_ACCOUNTS" /&gt;
    328     &lt;uses-permission android:name="android.permission.WAKE_LOCK" /&gt;
    329     &lt;uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" /&gt;
    330 
    331     &lt;permission android:name="com.example.gcm.permission.C2D_MESSAGE" 
    332         android:protectionLevel="signature" /&gt;
    333     &lt;uses-permission android:name="com.example.gcm.permission.C2D_MESSAGE" /&gt;
    334 
    335     &lt;application ...&gt;
    336         &lt;receiver
    337             android:name=".MyBroadcastReceiver"
    338             android:permission="com.google.android.c2dm.permission.SEND" &gt;
    339             &lt;intent-filter&gt;
    340                 &lt;action android:name="com.google.android.c2dm.intent.RECEIVE" /&gt;
    341                 &lt;action android:name="com.google.android.c2dm.intent.REGISTRATION" /&gt;
    342                 &lt;category android:name="com.example.gcm" /&gt;
    343             &lt;/intent-filter&gt;
    344         &lt;/receiver&gt;
    345         &lt;service android:name=".MyIntentService" /&gt;
    346     &lt;/application&gt;
    347 
    348 &lt;/manifest&gt;
    349 </pre>
    350 <h3 id="registering">Registering for GCM</h3>
    351 
    352 <p>An Android application needs to register with GCM servers before it can receive messages. To register, the application sends an Intent
    353 (<code>com.google.android.c2dm.intent.REGISTER</code>), with 2 extra parameters:
    354 </p>
    355 
    356 <ul>
    357   <li><code>sender</code> is the project ID of the account authorized to send messages
    358 to the Android application. </li>
    359   <li><code>app</code> is the Android application's ID, set with a <code>PendingIntent</code> to
    360 allow the registration service to extract Android application information. </li>
    361 </ul>
    362 
    363 <p>For example:</p>
    364 
    365 <pre class="prettyprint pretty-java">Intent registrationIntent = new Intent(&quot;com.google.android.c2dm.intent.REGISTER&quot;);
    366 // sets the app name in the intent
    367 registrationIntent.putExtra(&quot;app&quot;, PendingIntent.getBroadcast(this, 0, new Intent(), 0));
    368 registrationIntent.putExtra(&quot;sender&quot;, senderID);
    369 startService(registrationIntent);</pre>
    370 
    371 <p>This intent will be asynchronously sent to the GCM server, and the response will be delivered to
    372 the application as a <code>com.google.android.c2dm.intent.REGISTRATION</code> intent containing
    373 the registration ID assigned to the Android application running on that particular device.</p>
    374 
    375 <p>Registration is not complete until the Android application sends the registration ID
    376 to the 3rd-party application server, which in turn will use the registration ID to send
    377 messages to the application.</p>
    378 
    379 <h3 id="unregistering">Unregistering from GCM</h3>
    380 
    381 <p>To unregister from GCM, do the following:</p>
    382 
    383 <pre class="prettyprint pretty-java">Intent unregIntent = new Intent(&quot;com.google.android.c2dm.intent.UNREGISTER&quot;);
    384 unregIntent.putExtra(&quot;app&quot;, PendingIntent.getBroadcast(this, 0, new Intent(), 0));
    385 startService(unregIntent);
    386 </pre>
    387 
    388 <p>Similar to the registration request, this intent is sent asynchronously, and the response comes as a <code>com.google.android.c2dm.intent.REGISTRATION</code> intent.
    389 
    390 
    391 <h3 id="handling_intents">Handling Intents sent by GCM</h3>
    392 
    393 <p>As discussed in <a href="#manifest">Creating the Manifest</a>, the manifest
    394 defines a broadcast receiver for the <code>com.google.android.c2dm.intent.REGISTRATION</code> and <code>com.google.android.c2dm.intent.RECEIVE</code> intents.
    395 These <a href="{@docRoot}guide/components/intents-filters.html">intents</a> are sent by GCM to indicate that a device was registered (or unregistered), or to deliver messages, respectively.</p>
    396 
    397 <p>Handling these intents might require I/O operations (such as network calls to the 3rd party server), and 
    398 such operations should not be done in the receiver's <code>onReceive()</code> method.
    399 You may be tempted to spawn a new thread directly, but there are no guarantees that the process will run long enough for the thread to finish the work.  
    400 Thus the recommended way to handle the intents is to delegate them to a service, such as an {@link android.app.IntentService}. 
    401 For example:</p>
    402 
    403 
    404 <pre class="prettyprint pretty-java">
    405 public class MyBroadcastReceiver extends BroadcastReceiver {
    406 
    407     &#64;Override
    408     public final void onReceive(Context context, Intent intent) {
    409         MyIntentService.runIntentInService(context, intent);
    410         setResult(Activity.RESULT_OK, null, null);
    411     }
    412 }
    413 </pre>
    414 
    415 <p>Then in <code>MyIntentService</code>:</p>
    416 <pre class="prettyprint pretty-java">
    417 public class MyIntentService extends IntentService {
    418 
    419     private static PowerManager.WakeLock sWakeLock;
    420     private static final Object LOCK = MyIntentService.class;
    421     
    422     static void runIntentInService(Context context, Intent intent) {
    423         synchronized(LOCK) {
    424             if (sWakeLock == null) {
    425                 PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
    426                 sWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "my_wakelock");
    427             }
    428         }
    429         sWakeLock.acquire();
    430         intent.setClassName(context, MyIntentService.class.getName());
    431         context.startService(intent);
    432     }
    433     
    434     &#64;Override
    435     public final void onHandleIntent(Intent intent) {
    436         try {
    437             String action = intent.getAction();
    438             if (action.equals("com.google.android.c2dm.intent.REGISTRATION")) {
    439                 handleRegistration(intent);
    440             } else if (action.equals("com.google.android.c2dm.intent.RECEIVE")) {
    441                 handleMessage(intent);
    442             }
    443         } finally {
    444             synchronized(LOCK) {
    445                 sWakeLock.release();
    446             }
    447         }
    448     }
    449 }
    450 </pre>
    451 
    452 <p class="note"><strong>Note:</strong> your application must acquire a wake lock before starting the service&mdash;otherwise the device could be put to sleep before the service is started.</p>
    453 
    454 <h4 id="handling_reg">Handling Registration Results</h4>
    455 
    456 <p>When a <code>com.google.android.c2dm.intent.REGISTRATION</code> intent is received, it could potentially contain 3 extras: <code>registration_id</code>, <code>error</code>, and <code>unregistered</code>.
    457 
    458 <p>When a registration succeeds, <code>registration_id</code> contains the registration ID and the other extras are not set. 
    459 The application must ensure that the 3rd-party server receives the registration ID. It may do so by saving the registration ID and sending it to the server. 
    460 If the network is down or there are errors, the application should retry sending the registration ID when the network is up again or the next time it starts.</p>
    461 
    462 <p class="note"><strong>Note:</strong> Although the <code>com.google.android.c2dm.intent.REGISTRATION</code> intent is typically received after a request was made by the application, 
    463 Google may periodically refresh the registration ID. So the application must be prepared to handle it at any time.</p>
    464 
    465 <p>When an unregistration succeeds, only the <code>unregistered</code> extra is set, and similar to the registration workflow, 
    466 the application must contact the 3rd-party server to remove the registration ID (note that the registration ID is not available in the intent, 
    467 but the application should have saved the registration ID when it got it).<p>
    468 
    469 <p>If the application request (be it register or unregister) fails, the <code>error</code> will be set with an error code, and the other extras will not be set. 
    470 
    471 Here are the possible error codes:</p>
    472 
    473 <table>
    474   <tr>
    475     <th>Error Code</th>
    476     <th>Description</th>
    477   </tr>
    478   <tr>
    479     <td><code>SERVICE_NOT_AVAILABLE</code></td>
    480     <td>The device can't read the response, or there was a 500/503 from the
    481 server that can be retried later. The Android application should use exponential back-off and retry. See <a href="adv.html#retry">Advanced Topics</a> for more information. </td>
    482   </tr>
    483   <tr>
    484     <td><code>ACCOUNT_MISSING</code></td>
    485     <td>There is no Google account on the phone.  The Android application should ask the
    486 user to open the account manager and add a Google account. Fix on the device
    487 side.</td>
    488   </tr>
    489   <tr>
    490     <td><code>AUTHENTICATION_FAILED</code></td>
    491     <td>Bad Google Account password. The Android application should ask the user to enter his/her Google Account
    492 password, and let the user retry manually later. Fix on the device side.</td>
    493   </tr>
    494   <tr>
    495     <td><code>INVALID_SENDER</code></td>
    496     <td>The sender account is not recognized. This must be fixed on the Android application side. The developer must fix the application to provide the right <code>sender</code> extra in the <code>com.google.android.c2dm.intent.REGISTER</code> intent.</td>
    497   </tr>
    498   <tr>
    499     <td><code>PHONE_REGISTRATION_ERROR</code></td>
    500     <td> Incorrect phone registration with Google. This
    501 phone doesn't currently support GCM.</td>
    502   </tr>
    503   <tr>
    504     <td><code>INVALID_PARAMETERS</code></td>
    505     <td>The  request sent by the phone does not contain the expected parameters. This phone doesn't currently support GCM.</td>
    506   </tr>
    507 </table>
    508 
    509 
    510 
    511 
    512 <p>Here's an example on how to handle the registration in the <code>MyIntentService</code> example:</p>
    513 
    514 <pre class="prettyprint pretty-java">
    515 private void handleRegistration(Intent intent) {
    516     String registrationId = intent.getStringExtra("registration_id");
    517     String error = intent.getStringExtra("error");
    518     String unregistered = intent.getStringExtra("unregistered");       
    519     // registration succeeded
    520     if (registrationId != null) {
    521         // store registration ID on shared preferences
    522         // notify 3rd-party server about the registered ID
    523     }
    524         
    525     // unregistration succeeded
    526     if (unregistered != null) {
    527         // get old registration ID from shared preferences
    528         // notify 3rd-party server about the unregistered ID
    529     } 
    530         
    531     // last operation (registration or unregistration) returned an error;
    532     if (error != null) {
    533         if ("SERVICE_NOT_AVAILABLE".equals(error)) {
    534            // optionally retry using exponential back-off
    535            // (see <a href="adv.html#retry">Advanced Topics</a>)
    536         } else {
    537             // Unrecoverable error, log it
    538             Log.i(TAG, "Received error: " + error);
    539         }
    540     }
    541 }</pre>
    542 
    543 <h4 id="received_data">Handling Received Data</h4>
    544 
    545 <p>The <code>com.google.android.c2dm.intent.RECEIVE</code> intent is used by GCM to 
    546 deliver the messages sent by the 3rd-party server to the application running in the device.
    547 If the server included key-pair values in the <code>data</code> parameter, they are available as 
    548 extras in this intent, with the keys being the extra names. GCM also includes an  extra called 
    549 <code>from</code> which contains the sender ID as an string, and another called <code>collapse_key</code> containing the collapse key (when in use).
    550 
    551 <p>Here is an example, again using the <code>MyIntentReceiver</code> class:</p>
    552 
    553 <pre class="prettyprint pretty-java">
    554 private void handleMessage(Intent intent) {
    555     // server sent 2 key-value pairs, score and time
    556     String score = intent.getExtra("score");
    557     String time = intent.getExtra("time");
    558     // generates a system notification to display the score and time
    559 }</pre>
    560 
    561 <h3 id="testing">Developing and Testing Your Android Applications</h3>
    562 
    563 <p>Here are some guidelines for developing and testing an Android application
    564 that uses the GCM feature:</p>
    565 
    566 <ul>
    567   <li>To develop and test your Android applications, you need to run and debug the
    568 applications on an Android 2.2 system image that includes the necessary
    569 underlying Google services. </li>
    570   <li>To develop and debug on an actual device, you need a device running an
    571 Android 2.2 system image that includes the Google Play Store application. </li>
    572   <li>To develop and test on the Android Emulator, you need to download the
    573 Android 2.2 version of the Google APIs Add-On into your SDK using the <em>Android
    574 SDK and AVD Manager</em>. Specifically, you need to download the component named
    575 &quot;Google APIs by Google Inc, Android API 8&quot;. Then, you need to set up
    576 an AVD that uses that system image. </li>
    577   <li>If the GCM feature is critical to the Android application's function, be sure to
    578 set <code>android:minSdkVersion=&quot;8&quot;</code> in the manifest. This
    579 ensures that the Android application cannot be installed in an environment in which it
    580 could not run properly. </li>
    581 </ul>
    582 
    583 <h2 id="server">Role of the 3rd-party Application Server</h2>
    584 
    585 <p>Before you can write client Android applications that use the GCM feature, you must
    586 have an  application server that meets the following criteria:</p>
    587 
    588 <ul>
    589   <li>Able to communicate with your client.</li>
    590   <li>Able to  fire off HTTPS requests to the GCM server.</li>
    591   <li>Able to handle requests and resend then as needed, using <a href="http://en.wikipedia.org/wiki/Exponential_backoff">exponential back-off.</a></li>
    592   <li>Able to store the API key and client registration IDs. The
    593 API key is included in the header of POST requests that send
    594 messages.</li>
    595 </ul>
    596 
    597 <h3 id="send-msg">Sending Messages</h3>
    598 <p>This section describes how the 3rd-party application server sends messages to one or more mobile devices. Note the following:</p>
    599 <ul>
    600   <li>A 3rd-party application server can either send messages to a single device or to multiple devices. A message sent to multiple devices simultaneously is called a <em>multicast message</em>.</li>
    601   
    602   <li>You have 2 choices in how you construct requests and responses: plain text or JSON.</li>
    603   <li>However, to send multicast messages, you must use JSON. Plain text will not work.</li>
    604 </ul>
    605 <p>Before the 3rd-party application server can send a  message to an
    606   Android application, it must have received a registration ID from it.</p>
    607 <h4 id="request">Request format</h4>
    608 <p>To send a  message, the application server issues a POST request to <code>https://android.googleapis.com/gcm/send</code>.</p>
    609 <p>A  message request is made of 2 parts: HTTP header and HTTP body.</p>
    610 
    611 <p>The HTTP header must contain the following headers:</p>
    612 <ul>
    613   <li><code>Authorization</code>: key=YOUR_API_KEY</li>
    614   <li><code>Content-Type</code>: <code>application/json</code> for JSON; <code>application/x-www-form-urlencoded;charset=UTF-8</code> for plain text.
    615   </li>
    616 </ul>
    617 
    618 <p>For example:
    619 </p>
    620 <pre>Content-Type:application/json
    621 Authorization:key=AIzaSyB-1uEai2WiUapxCs2Q0GZYzPu7Udno5aA
    622 
    623 {
    624   "registration_ids" : ["APA91bHun4MxP5egoKMwt2KZFBaFUH-1RYqx..."],
    625   "data" : {
    626     ...
    627   },
    628 }</pre>
    629 <p class="note">
    630   <p><strong>Note:</strong> If <code>Content-Type</code> is omitted, the format is assumed to be plain text.</p>
    631 </p>
    632 
    633 <p>The HTTP body content depends on whether you're using JSON or plain text. For JSON, it must contain a string representing a JSON object with the following fields:</p>
    634 <table>
    635   <tr>
    636     <th>Field</th>
    637     <th>Description</th>
    638   </tr>
    639   <tr>
    640     <td><code>registration_ids</code></td>
    641     <td>A string array with the list of devices (registration IDs) receiving the message. It must contain at least 1 and at most 1000 registration IDs. To send a multicast message, you must use JSON. For sending a single message to a single device, you could use a JSON object with just 1 registration id, or plain text (see below). Required.</td>
    642   </tr>
    643   <tr>
    644     <td><code>collapse_key</code></td>
    645     <td>An arbitrary string (such as &quot;Updates Available&quot;) that is used to collapse a group of like messages
    646 when the device is offline, so that only the last message gets sent to the
    647 client. This is intended to avoid sending too many messages to the phone when it
    648 comes back online. Note that since there is no guarantee of the order in which
    649 messages get sent, the &quot;last&quot; message may not actually be the last
    650 message sent by the application server. See <a href="adv.html#collapsible">Advanced Topics</a> for more discussion of this topic. Optional, unless you are using the <code>time_to_live</code> parameter&mdash;in that case, you must also specify a <code>collapse_key</code>.</td>
    651   </tr>
    652   <tr>
    653     <td><code>data</code></td>
    654     <td>A JSON object whose fields represents the key-value pairs of the message's payload data. If present, the payload data it will be
    655 included in the Intent as application data, with the key being the extra's name. For instance, <code>"data":{"score":"3x1"}</code> would result in an intent extra named <code>score</code> whose value is the string <code>3x1</code>. 
    656 There is no limit on the number of key/value pairs, though there is a limit on the total size of the message (4kb). The values could be any JSON object, but we recommend using strings, since the values will be converted to strings in the GCM server anyway. If you want to include objects or other non-string data types (such as integers or booleans), you have to do the conversion to string yourself. Also note that the key cannot be a reserved word (<code>from</code> or any word starting with <code>google.</code>). To complicate things slightly, there are some reserved words (such as <code>collapse_key</code>) that are technically allowed in payload data. However, if the request also contains the word, the value in the request will overwrite the value in the payload data. Hence using words that are defined as field names in this table is not recommended, even in cases where they are technically allowed. Optional.</td>
    657 
    658   </tr>
    659   <tr>
    660     <td><code>delay_while_idle</code></td>
    661     <td>If included, indicates that the message should not be sent immediately
    662 if the device is idle. The server will wait for the device to become active, and
    663 then only the last message for each <code>collapse_key</code> value will be
    664 sent. Optional. The default value is <code>false</code>, and must be a JSON boolean.</td>
    665   </tr>
    666   <tr>
    667     <td><code>time_to_live</code></td>
    668     <td>How long (in seconds) the message should be kept on GCM storage if the device is offline. Optional (default time-to-live is 4 weeks, and must be set as a JSON number). If you use this parameter, you must also specify a <code>collapse_key</code>.</td>
    669   </tr>
    670 </table>
    671 
    672 <p>If you are using plain text instead of JSON, the message fields must be set as HTTP parameters sent in the body, and their syntax is slightly different, as described below:
    673 <table>
    674   <tr>
    675     <th>Field</th>
    676     <th>Description</th>
    677   </tr>
    678   <tr>
    679     <td><code>registration_id</code></td>
    680     <td>Must contain the registration ID of the single device receiving the message. Required.</td>
    681   </tr>
    682   <tr>
    683     <td><code>collapse_key</code></td>
    684     <td>Same as JSON (see previous table). Optional.</td>
    685   </tr>
    686   <tr>
    687     <td><code>data.&lt;key&gt;</code></td>
    688     <td>Payload data, expressed as parameters prefixed with <code>data.</code> and suffixed as the key. For instance, a parameter of <code>data.score=3x1</code> would result in an intent extra named <code>score</code> whose value is the string <code>3x1</code>. There is no limit on the number of key/value parameters, though there is a limit on the total size of the  message. Also note that the key cannot be a reserved word (<code>from</code> or any word starting with 
    689 <code>google.</code>). To complicate things slightly, there are some reserved words (such as <code>collapse_key</code>) that are technically allowed in payload data. However, if the request also contains the word, the value in the request will overwrite the value in the payload data. Hence using words that are defined as field names in this table is not recommended, even in cases where they are technically allowed. Optional.</td>
    690   </tr>
    691   <tr>
    692     <td><code>delay_while_idle</code></td>
    693     <td>Should be represented as <code>1</code> or <code>true</code> for <code>true</code>, anything else for <code>false</code>. Optional. The default value is <code>false</code>.</td>
    694   </tr>
    695   <tr>
    696     <td><code>time_to_live</code></td>
    697     <td>Same as JSON (see previous table). Optional.</td>
    698   </tr>
    699 </table>
    700 
    701 <p>If you want to test your request (either JSON or plain text) without delivering the message to the devices, you can set an optional HTTP parameter called <code>dry_run</code> with the value <code>true</code>. The result will be almost identical to running the request without this parameter, except that the message will not be delivered to the devices. Consequently, the response will contain fake IDs for the message and multicast fields (see <a href="#response">Response format</a>).</p>
    702 
    703   <h4 id="example-requests">Example requests</h4>
    704   <p>Here is the smallest possible request (a message without any parameters and just one recipient) using JSON:</p>
    705   <pre class="prettyprint pretty-json">{ &quot;registration_ids&quot;: [ &quot;42&quot; ] }</pre>
    706   
    707   <p>And here the same example using plain text:</p>
    708   <pre class="prettyprint">registration_id=42</pre>
    709   
    710   <p> Here is a message with a payload and 6 recipients:</p>
    711   <pre class="prettyprint pretty-HTML">{ "data": {
    712     "score": "5x1",
    713     "time": "15:10"
    714   },
    715   "registration_ids": ["4", "8", "15", "16", "23", "42"]
    716 }</pre>
    717   <p>Here is a message with all optional fields set and 6 recipients:</p>
    718   <pre class="prettyprint pretty-json">{ "collapse_key": "score_update",
    719   "time_to_live": 108,
    720   "delay_while_idle": true,
    721   "data": {
    722     "score": "4x8",
    723     "time": "15:16.2342"
    724   },
    725   "registration_ids":["4", "8", "15", "16", "23", "42"]
    726 }</pre>
    727   <p>And here is the same message using plain-text format (but just 1 recipient):  </p>
    728   
    729   <pre class="prettyprint">collapse_key=score_update&amp;time_to_live=108&amp;delay_while_idle=1&amp;data.score=4x8&amp;data.time=15:16.2342&amp;registration_id=42
    730   </pre>
    731 
    732   <p class="note"><strong>Note:</strong> If your organization has a firewall that restricts the traffic to or from the Internet, you'll need to configure it to allow connectivity with GCM. The ports to open are: 5228, 5229, and 5230. GCM typically only uses 5228, but it sometimes uses 5229 and 5230.
    733 GCM doesn't provide specific IPs. It changes IPs frequently. We recommend against using ACLs but if you must use them, take a broad approach such as the method suggested in <a href="http://support.google.com/code/bin/answer.py?hl=en&answer=62464">this support link</a>.
    734 </p>
    735 
    736 <h4 id="response">Response format</h4>
    737 
    738 <p>There are two possible outcomes when trying to send a message:</p>
    739 <ul>
    740   <li>The message is processed successfully.</li>
    741   <li>The GCM server rejects the request.</li>
    742 </ul>
    743 
    744 <p>When the messge is processed successfully, the HTTP response has a 200 status and the body contains more information about the status of the message (including possible errors). When the request is rejected, 
    745 the HTTP response contains a non-200 status code (such as 400, 401, or 503).</p>
    746 
    747 <p>The following table summarizes the statuses that the HTTP response header might contain. Click the troubleshoot link for advice on how to deal with each type of error.</p>
    748 <table border=1>
    749   <tr>
    750     <th>Response</th>
    751     <th>Description</th>
    752   </tr>
    753   <tr>
    754     <td>200</td>
    755     <td>Message was processed successfully. The response body will contain more details about the message status, but its format will depend whether the request was JSON or plain text. See <a href="#success">Interpreting a success response</a> for more details.</td>
    756   </tr>
    757   <tr>
    758     <td>400</td>
    759     <td><span id="internal-source-marker_0.2">Only applies for JSON requests. Indicates that the request could not be parsed as JSON, or it contained invalid fields (for instance, passing a string where a number was expected). The exact failure reason is described in the response and the problem should be addressed before the request can be retried.</td>
    760   </tr>
    761   <tr>
    762     <td>401</td>
    763     <td>There was an error authenticating the sender account. <a href="#auth_error">Troubleshoot</a></td>
    764   </tr>
    765   <tr>
    766     <td>500</td>
    767     <td>There was an internal error in the GCM server while trying to process the request. <a href="#internal_error">Troubleshoot</a></td>
    768   </tr>
    769   <tr>
    770     <td>503</td>
    771     <td>Indicates that the server is temporarily unavailable (i.e., because of timeouts, etc ). Sender must retry later, honoring any <code>Retry-After</code> header
    772       included in the response. Application servers must implement exponential back-off. The GCM server took too long to process the request. <a href="#internal_error">Troubleshoot</a></td>
    773   </tr>
    774 </table>
    775 
    776 <h4 id="success">Interpreting a success response</h4>
    777 <p>When a JSON request is successful (HTTP status code 200), the response body contains a JSON object with the following fields:</p>
    778 <table>
    779   <tr>
    780     <th>Field</th>
    781     <th>Description</th>
    782   </tr>
    783   <tr>
    784     <td><code>multicast_id</code></td>
    785     <td>Unique ID (number) identifying the multicast message.</td>
    786   </tr>
    787   <tr>
    788     <td><code>success</code></td>
    789     <td>Number of messages that were processed without an error.</td>
    790   </tr>
    791   <tr>
    792     <td><code>failure</code></td>
    793     <td>Number of messages that could not be processed.</td>
    794   </tr>
    795   <tr>
    796     <td><code>canonical_ids</code></td>
    797     <td>Number of results that contain a canonical registration ID. See <a href="adv.html#canonical">Advanced Topics</a> for more discussion of this topic.</td>
    798   </tr>
    799   <tr>
    800     <td><code>results</code></td>
    801     <td>Array of objects representing the status of the messages processed. The objects are listed in the same order as the request (i.e., for each registration ID in the request, its result is listed in the same index in the response) and they can have these fields:<br>
    802       <ul>
    803         <li><code>message_id</code>: String representing the message when it was successfully processed.</li>
    804         <li><code>registration_id</code>: If set,  means that GCM processed the message but it has another canonical registration ID for that device, so sender should replace the IDs on future requests (otherwise they might be rejected). This field is never set if there is an error in the request.<br />
    805         </li>
    806         <li><code>error</code>: String describing an error that occurred while processing the message for that recipient. The possible values are the same as documented in the above table, plus &quot;Unavailable&quot;  (meaning GCM servers were busy and could not process the message for that  particular recipient, so it could be retried).</li>
    807     </ul></td>
    808   </tr>
    809 </table>
    810 <p>If the value of <code>failure</code> and <code>canonical_ids</code> is 0, it's not necessary to parse the remainder of the response. Otherwise, we recommend that you iterate through the results field and do the following for each object in that list:</p>
    811 <ul>
    812   <li>If <code>message_id</code> is set, check for <code>registration_id</code>:
    813     <ul>
    814       <li>If <code>registration_id</code> is set, replace the original ID with the new value (canonical ID) in your server database. Note that the original ID is not part of the result, so you need to obtain it from the list of <code>registration_ids</code> passed in the request (using the same index).</li>
    815     </ul>
    816   </li>
    817   <li>Otherwise, get the value of <code>error</code>:
    818     <ul>
    819       <li>If it is <code>Unavailable</code>, you could retry to send it in another request.</li>
    820       <li>If it is <code>NotRegistered</code>, you should remove the registration ID from your server database because the application was uninstalled from the device or it does not have a broadcast receiver configured to receive <code>com.google.android.c2dm.intent.RECEIVE</code> intents.</li>
    821       <li>Otherwise, there is something wrong in the registration ID passed in the request; it is probably a non-recoverable error that will also require removing the registration from the server database. See <a href="#error_codes">Interpreting an error response</a> for all possible error values.</li>
    822     </ul>
    823   </li>
    824 </ul>
    825 
    826 <p>When a plain-text request is successful (HTTP status code 200), the response body contains 1 or 2 lines in the form of key/value pairs.
    827 The first line is always available and its content is either <code>id=<em>ID of sent message</em></code> or <code>Error=<em>GCM error code</em></code>. The second line, if available, 
    828 has the format of <code>registration_id=<em>canonical ID</em></code>. The second line is optional, and it can only be sent if the first line is not an error. We recommend handling the plain-text response in a similar way as handling the JSON response:</p>
    829 <ul>
    830   <li>If first line starts with <code>id</code>, check second line:
    831     <ul>
    832       <li>If second line starts with <code>registration_id</code>, gets its value and replace the registration IDs in your server database.</li>
    833     </ul>
    834   </li>
    835   <li>Otherwise, get the value of <code>Error</code>:
    836     <ul>
    837       <li>If it is <code>NotRegistered</code>, remove the registration ID from your server database.</li>
    838       <li>Otherwise, there is probably a non-recoverable error (<strong>Note: </strong>Plain-text requests will never return <code>Unavailable</code> as the error code, they would have returned a 500 HTTP status instead).</li>
    839     </ul>
    840   </li>
    841 </ul>
    842 
    843 <h4 id="error_codes">Interpreting an error response</h4>
    844 <p>Here are the recommendations for handling the different types of error that might occur when trying to send a message to a device:</p>
    845 
    846 <dl>
    847 <dt id="missing_reg"><strong>Missing Registration ID</strong></dt>
    848 <dd>Check that the request contains a registration ID (either in the <code>registration_id</code> parameter in a plain text message, or in the <code>registration_ids</code> field in JSON). 
    849 <br/>Happens when error code is <code>MissingRegistration</code>.</dd>
    850 
    851 <dt id="invalid_reg"><strong>Invalid Registration ID</strong></dt>
    852 <dd>Check the formatting of the registration ID that you pass to the server. Make sure it matches the registration ID the phone receives in the <code>com.google.android.c2dm.intent.REGISTRATION</code> intent and that you're not truncating it or adding additional characters. 
    853 <br/>Happens when error code is <code>InvalidRegistration</code>.</dd>
    854 
    855 <dt id="mismatched_sender"><strong>Mismatched Sender</strong></dt>
    856 <dd>A registration ID is tied to a certain group of senders. When an application registers for GCM usage, it must specify which senders are allowed to send messages. Make sure you're using one of those when trying to send messages to the device. If you switch to a different sender, the existing registration IDs won't work. 
    857 Happens when error code is <code>MismatchSenderId</code>.</dd>
    858 
    859 <dt id="unreg_device"><strong>Unregistered Device</strong></dt>
    860 <dd>An existing registration ID may cease to be valid in a number of scenarios, including:
    861 <ul>
    862   <li>If the application manually unregisters by issuing a <span class="prettyprint pretty-java"><code>com.google.android.c2dm.intent.UNREGISTER</code></span><code> </code>intent.</li>
    863   <li>If the application is automatically unregistered, which can happen (but is not guaranteed) if the user uninstalls the application.</li>
    864   <li>If the registration ID expires. Google might decide to refresh registration IDs. </li>
    865   <li>If the application is updated but the new version does not have a broadcast receiver configured to receive <code>com.google.android.c2dm.intent.RECEIVE</code> intents.</li>
    866 </ul>
    867 For all these cases, you should remove this registration ID from the 3rd-party server and stop using it to send 
    868 messages. 
    869 <br/>Happens when error code is <code>NotRegistered</code>.</dd>
    870 
    871 <dt id="big_msg"><strong>Message Too Big</strong></dt>
    872   <dd>The total size of the payload data that is included in a message can't exceed 4096 bytes. Note that this includes both the size of the keys as well as the values. 
    873 <br/>Happens when error code is <code>MessageTooBig</code>.</dd>
    874 
    875 <dt id="invalid_datakey"><strong>Invalid Data Key</strong></dt>
    876 <dd>The payload data contains a key (such as <code>from</code> or any value prefixed by <code>google.</code>) that is used internally by GCM in the  <code>com.google.android.c2dm.intent.RECEIVE</code> Intent and cannot be used. Note that some words (such as <code>collapse_key</code>) are also used by GCM but are allowed in the payload, in which case the payload value will be overridden by the GCM value. 
    877 <br />
    878 Happens when the error code is <code>InvalidDataKey</code>.</dd>
    879 
    880 <dt id="ttl_error"><strong>Invalid Time To Live</strong></dt>
    881   <dd>The value for the Time to Live field must be an integer representing a duration in seconds between 0 and 2,419,200 (4 weeks). Happens when error code is <code>InvalidTtl</code>.
    882 </dd>
    883 
    884   <dt id="auth_error"><strong>Authentication Error</strong></dt>
    885   <dd>The sender account that you're trying to use to send a message couldn't be authenticated. Possible causes are: <ul>
    886 <li>Authorization header missing or with invalid syntax.</li>
    887 <li>Invalid project ID sent as key.</li>
    888 <li>Key valid but with GCM service disabled.</li>
    889 <li>Request originated from a server not whitelisted in the Server Key IPs.</li>
    890 
    891 </ul>
    892 Check that the token you're sending inside the <code>Authorization</code> header is the correct API key associated with your project. You can check the validity of your API key by running the following command:<br/>
    893 
    894 
    895 <pre># api_key=YOUR_API_KEY
    896 
    897 # curl --header "Authorization: key=$api_key" --header Content-Type:"application/json" https://android.googleapis.com/gcm/send  -d "{\"registration_ids\":[\"ABC\"]}"</pre>
    898 
    899 
    900 
    901 If you receive a 401 HTTP status code, your API key is not valid. Otherwise you should see something like this:<br/>
    902 
    903 <pre>
    904 {"multicast_id":6782339717028231855,"success":0,"failure":1,"canonical_ids":0,"results":[{"error":"InvalidRegistration"}]}
    905 </pre>
    906 If you want to confirm the validity of a registration ID, you can do so by replacing "ABC" with the registration ID.
    907 <br/>
    908 Happens when the HTTP status code is 401.
    909 
    910   <dt id="timeout"><strong>Timeout</strong></dt>
    911 
    912 <dd>The server couldn't process the request in time. You should retry the
    913 same request, but you MUST obey the following requirements:
    914 
    915 <ul>
    916 
    917 <li>Honor the <code>Retry-After</code> header if it's included in the response from the GCM server.</li>
    918         
    919         
    920 <li>Implement exponential back-off in your retry mechanism. This means an
    921 exponentially increasing delay after each failed retry (e.g. if you waited one
    922 second before the first retry, wait at least two second before the next one,
    923 then 4 seconds and so on). If you're sending multiple messages, delay each one
    924 independently by an additional random amount to avoid issuing a new request for
    925 all messages at the same time.</li>
    926     
    927 
    928 Senders that cause problems risk being blacklisted. 
    929 <br />
    930 Happens when the HTTP status code is 503, or when the <code>error</code> field of a JSON object in the results array is <code>Unavailable</code>.
    931 </dd>
    932 
    933 <dt id="internal_error"><strong>Internal Server Error</strong></dt>
    934 
    935 <dd>
    936 The server encountered an error while trying to process the request. You
    937 could retry the same request (obeying the requirements listed in the <strong>Timeout</strong>
    938 section), but if the error persists, please report the problem in the <a href="https://groups.google.com/forum/?fromgroups#!forum/android-gcm">android-gcm group</a>.
    939 <br /> 
    940 Senders that cause problems risk being blacklisted. 
    941 <br />
    942 Happens when the HTTP status code is 500, or when the <code>error</code> field of a JSON
    943 object in the results array is <code>InternalServerError</code>.
    944 </dd>
    945 
    946 
    947 </dl>
    948 <h4>Example responses</h4>
    949 <p>This section shows a few examples of responses indicating messages that were processed successfully. See <a href="#example-requests">Example requests</a> for the requests these responses are based on.</p>
    950 <p> Here is a simple case of a JSON message successfully sent to one recipient without canonical IDs in the response:</p>
    951 <pre class="prettyprint pretty-json">{ "multicast_id": 108,
    952   "success": 1,
    953   "failure": 0,
    954   "canonical_ids": 0,
    955   "results": [
    956     { "message_id": "1:08" }
    957   ]
    958 }</pre>
    959 
    960 <p>Or if the request was in plain-text format:</p>
    961 <pre class="prettyprint">id=1:08
    962 </pre>
    963 
    964 <p>Here are JSON results for 6 recipients (IDs 4, 8, 15, 16, 23, and 42 respectively) with 3 messages successfully processed, 1 canonical registration ID returned, and 3 errors:</p>
    965 <pre class="prettyprint pretty-json">{ "multicast_id": 216,
    966   "success": 3,
    967   "failure": 3,
    968   "canonical_ids": 1,
    969   "results": [
    970     { "message_id": "1:0408" },
    971     { "error": "Unavailable" },
    972     { "error": "InvalidRegistration" },
    973     { "message_id": "1:1516" },
    974     { "message_id": "1:2342", "registration_id": "32" },
    975     { "error": "NotRegistered"}
    976   ]
    977 }
    978 </pre>
    979 <p> In this example:</p>
    980 <ul>
    981   <li>First message: success, not required.</li>
    982   <li>Second message: should be resent (to registration ID 8).</li>
    983   <li>Third message: had an unrecoverable error (maybe the value got corrupted in the database).</li>
    984   <li>Fourth message: success, nothing required.</li>
    985   <li>Fifth message: success, but the registration ID should be updated in the server database (from 23 to 32).</li>
    986   <li>Sixth message: registration ID (42) should be removed from the server database because the application was uninstalled from the device.</li>
    987 </ul>
    988 <p>Or if just the 4th message above was sent using plain-text format:</p>
    989 <pre class="prettyprint">Error=InvalidRegistration
    990 </pre>
    991 <p>If the 5th message above was also sent using plain-text format:</p>
    992 <pre class="prettyprint">id=1:2342
    993 registration_id=32
    994 </pre>
    995 
    996 
    997 <h3 id="stats">Viewing statistics</h3>
    998 
    999 <p>To view  statistics and any error messages for your GCM applications:</p>
   1000 <ol>
   1001   <li> Go to the <code><a href="http://play.google.com/apps/publish">Android Developer Console</a></code>.</li>
   1002   <li>Login with your developer account. 
   1003   <p>You will see a page that has a list of all of your apps.</p></li>
   1004   <li> Click on the &quot;statistics&quot; link next to the app for which you want to view GCM stats. 
   1005   <p>Now you are on the statistics page.</p> </li>
   1006   <li>Go to the drop-down menu and select the GCM metric you want to view. 
   1007   </li>
   1008 </ol>
   1009 <p class="note"><strong>Note:</strong> Stats on the Google API Console are not enabled for GCM. You must use the <a href="http://play.google.com/apps/publish">Android Developer Console</a>.</p>
   1010 
   1011 <h2 id="example">Examples</h2>
   1012 <p>See the <a href="demo.html">GCM Demo Application</a> document.</p>
   1013 
   1014