title: C2DM Broadcast Intent giving an ANR. How to avoid it?
body: <p>I am using the tutorial from <a href="http://www.vogella.de/articles/AndroidCloudToDeviceMessaging/article.html" rel="nofollow">C2DM Tutorial</a> and when I run with this code in my app(my app has many threads and also I run this C2DMessaging.register(getApplicationContext(), SENDERS_EMAIL_ID); in one more thread.</p>
  
  <p>But still even after I run this on a separate thread I get the below error message and an ANR pops up, thought I see that in my background my app started perfectly!!!!</p>
  
  <p>The way I start the C2DM.register(...) is </p>
  
  <pre><code>            new Thread() {
                  public void run() {
                      try{
                          C2DMessaging.register(getApplicationContext(), SENDERS_EMAIL_ID);
  
                      } catch (Exception e) {
                          Log.e(TAG, e.getMessage());
                      }
                  }
              }.start();
  </code></pre>
  
  <p>The error log that I get when I do this is</p>
  
  <pre><code>E/ActivityManager(  162): ANR in com.example.myapp
  E/ActivityManager(  162): Reason: Broadcast of Intent { act=com.google.android.c2dm.intent.REGISTRATION cat=[com.example.myapp] flg=0x10 cmp=com.example.myapp/.c2dm.C2DMBroadcastReceiver (has extras) }
  E/ActivityManager(  162): Load: 0.63 / 0.24 / 0.32
  E/ActivityManager(  162): CPU usage from 5001ms to 0ms ago:
  E/ActivityManager(  162):   98% 29787/com.example.myapp: 98% user + 0.4% kernel / faults: 2 minor
  E/ActivityManager(  162):   1% 162/system_server: 0.4% user + 0.6% kernel / faults: 93 minor
  E/ActivityManager(  162):   0.8% 127/sdcard: 0% user + 0.8% kernel
  E/ActivityManager(  162):   0.6% 128/adbd: 0% user + 0.6% kernel / faults: 182 minor
  E/ActivityManager(  162):   0.6% 224/dhd_dpc: 0% user + 0.6% kernel
  E/ActivityManager(  162):   0.2% 240/com.android.phone: 0.2% user + 0% kernel
  E/ActivityManager(  162):   0.2% 29429/kworker/u:3: 0% user + 0.2% kernel
  E/ActivityManager(  162): 54% TOTAL: 49% user + 1.9% kernel + 2.1% iowait + 0.1% softirq
  E/ActivityManager(  162): CPU usage from 525ms to 1057ms later with 99% awake:
  E/ActivityManager(  162):   98% 29787/com.example.myapp: 96% user + 1.8% kernel
  E/ActivityManager(  162):     96% 29787/com.example.myapp: 96% user + 0% kernel
  E/ActivityManager(  162):   5.6% 162/system_server: 0% user + 5.6% kernel
  E/ActivityManager(  162):     5.6% 172/ActivityManager: 1.8% user + 3.7% kernel
  E/ActivityManager(  162):     1.8% 170/SensorService: 1.8% user + 0% kernel
  E/ActivityManager(  162):   2.7% 127/sdcard: 0% user + 2.7% kernel
  E/ActivityManager(  162):   2.7% 128/adbd: 0% user + 2.7% kernel / faults: 156 minor
  E/ActivityManager(  162):     2.7% 128/adbd: 0% user + 2.7% kernel
  E/ActivityManager(  162):     1.3% 11683/adbd: 0% user + 1.3% kernel
  E/ActivityManager(  162):   1.3% 224/dhd_dpc: 0% user + 1.3% kernel
  </code></pre>
  
  <p>Any pointers will be really appreciated!</p>
  
  <p>Thanks.</p>
  
  <p>The code for C2DMBroadcastReceiver is</p>
  
  <pre><code>import android.app.Activity;
  import android.content.BroadcastReceiver;
  import android.content.Context;
  import android.content.Intent;
  
  /**
   * Helper class to handle BroadcastReciver behavior.
   * - can only run for a limited amount of time - it must start a real service 
   * for longer activity
   * - must get the power lock, must make sure it's released when all done.
   * 
   */
  public class C2DMBroadcastReceiver extends BroadcastReceiver {
  
      @Override
      public final void onReceive(Context context, Intent intent) {
          // To keep things in one place.
          C2DMBaseReceiver.runIntentInService(context, intent);
          setResult(Activity.RESULT_OK, null /* data */, null /* extra */);        
      }
  }
  </code></pre>
  
  <p>for the C2DMBaseReceiver it is </p>
  
  <pre><code>import java.io.IOException;
  
  import android.app.AlarmManager;
  import android.app.IntentService;
  import android.app.PendingIntent;
  import android.content.Context;
  import android.content.Intent;
  import android.os.PowerManager;
  import android.util.Log;
  
  /**
   * Base class for C2D message receiver. Includes constants for the strings used
   * in the protocol.
   */
  public abstract class C2DMBaseReceiver extends IntentService {
      private static final String C2DM_RETRY                  = "com.google.android.c2dm.intent.RETRY";
      public static final String REGISTRATION_CALLBACK_INTENT = "com.google.android.c2dm.intent.REGISTRATION";
      private static final String C2DM_INTENT                 = "com.google.android.c2dm.intent.RECEIVE";
      private static final String TAG                         = "MyApp";
      // Extras in the registration callback intents.
      public static final String EXTRA_UNREGISTERED           = "unregistered";
      public static final String EXTRA_ERROR                  = "error";
      public static final String EXTRA_REGISTRATION_ID        = "registration_id";
  
      public static final String ERR_SERVICE_NOT_AVAILABLE    = "SERVICE_NOT_AVAILABLE";
      public static final String ERR_ACCOUNT_MISSING          = "ACCOUNT_MISSING";
      public static final String ERR_AUTHENTICATION_FAILED    = "AUTHENTICATION_FAILED";
      public static final String ERR_TOO_MANY_REGISTRATIONS   = "TOO_MANY_REGISTRATIONS";
      public static final String ERR_INVALID_PARAMETERS       = "INVALID_PARAMETERS";
      public static final String ERR_INVALID_SENDER           = "INVALID_SENDER";
      public static final String ERR_PHONE_REGISTRATION_ERROR = "PHONE_REGISTRATION_ERROR";
  
      private static final String WAKELOCK_KEY                = "MyApp";
  
      private static PowerManager.WakeLock mWakeLock;
      private final String senderId;
  
      /**
       * The C2DMReceiver class must create a no-arg constructor and pass the
       * sender id to be used for registration.
       */
      public C2DMBaseReceiver(String senderId) {
          // senderId is used as base name for threads, etc.
          super(senderId);
          this.senderId = senderId;
      }
  
      /**
       * Called when a cloud message has been received.
       */
      protected abstract void onMessage(Context context, Intent intent);
  
      /**
       * Called on registration error. Override to provide better error messages.
       * 
       * This is called in the context of a Service - no dialog or UI.
       */
      public abstract void onError(Context context, String errorId);
  
      /**
       * Called when a registration token has been received.
       */
      public void onRegistered(Context context, String registrationId)
              throws IOException {
          // registrationId will also be saved
      }
  
      /**
       * Called when the device has been unregistered.
       */
      public void onUnregistered(Context context) {
      }
  
      @Override
      public final void onHandleIntent(Intent intent) {
          try {
              Context context = getApplicationContext();
              if (intent.getAction().equals(REGISTRATION_CALLBACK_INTENT)) {
                  handleRegistration(context, intent);
              } else if (intent.getAction().equals(C2DM_INTENT)) {
                  onMessage(context, intent);
              } else if (intent.getAction().equals(C2DM_RETRY)) {
                  C2DMessaging.register(context, senderId);
              }
          } finally {
              // Release the power lock, so phone can get back to sleep.
              // The lock is reference counted by default, so multiple
              // messages are ok.
  
              // If the onMessage() needs to spawn a thread or do something else,
              // it should use it's own lock.
              mWakeLock.release();
          }
      }
  
      /**
       * Called from the broadcast receiver. Will process the received intent,
       * call handleMessage(), registered(), etc. in background threads, with a
       * wake lock, while keeping the service alive.
       */
      static void runIntentInService(Context context, Intent intent) {
          if (mWakeLock == null) {
              // This is called from BroadcastReceiver, there is no init.
              PowerManager pm = (PowerManager) context
                      .getSystemService(Context.POWER_SERVICE);
              mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
                      WAKELOCK_KEY);
          }
          mWakeLock.acquire();
  
          // Use a naming convention, similar with how permissions and intents are
          // used. Alternatives are introspection or an ugly use of statics.
          String receiver = context.getPackageName() + ".c2dm.MyC2dmReceiver";
          intent.setClassName(context, receiver);
  
          context.startService(intent);
  
      }
  
      private void handleRegistration(final Context context, Intent intent) {
          final String registrationId = intent.getStringExtra(EXTRA_REGISTRATION_ID);
          String error = intent.getStringExtra(EXTRA_ERROR);
          String removed = intent.getStringExtra(EXTRA_UNREGISTERED);
  
          if (Log.isLoggable(TAG, Log.DEBUG)) {
              Log.d(TAG, "dmControl: registrationId = " + registrationId
                      + ", error = " + error + ", removed = " + removed);
          }
  
          if (removed != null) {
              // Remember we are unregistered
              C2DMessaging.clearRegistrationId(context);
              onUnregistered(context);
              return;
          } else if (error != null) {
              // we are not registered, can try again
              C2DMessaging.clearRegistrationId(context);
              // Registration failed
              Log.e(TAG, "Registration error " + error);
              onError(context, error);
              if ("SERVICE_NOT_AVAILABLE".equals(error)) {
                  long backoffTimeMs = C2DMessaging.getBackoff(context);
  
                  Log.d(TAG, "Scheduling registration retry, backoff = "
                          + backoffTimeMs);
                  Intent retryIntent = new Intent(C2DM_RETRY);
                  PendingIntent retryPIntent = PendingIntent
                          .getBroadcast(context, 0 /* requestCode */, retryIntent,
                                  0 /* flags */);
  
                  AlarmManager am = (AlarmManager) context
                          .getSystemService(Context.ALARM_SERVICE);
                  am.set(AlarmManager.ELAPSED_REALTIME, backoffTimeMs,
                          retryPIntent);
  
                  // Next retry should wait longer.
                  backoffTimeMs *= 2;
                  C2DMessaging.setBackoff(context, backoffTimeMs);
              }
          } else {
              try {
                  onRegistered(context, registrationId);
                  C2DMessaging.setRegistrationId(context, registrationId);
              } catch (IOException ex) {
                  Log.e(TAG, "Registration error " + ex.getMessage());
              }
          }
      }
  }
  </code></pre>