Bug 1270870 - Check profile when delivering pending push message; r=nalexander
authorJim Chen <nchen@mozilla.com>
Tue, 24 May 2016 01:11:16 -0400
changeset 370101 feb13c8b708aade4acf07e520682c2a9f9328544
parent 370100 8db10fbfc5067ddcc5509041284e2a6dabab6cf7
child 370102 5af4954d7140d96a04da145ec9d9df393375054c
child 370130 fcefb418df20a2a4081dd0409fa2bb2e58e651c6
child 370132 6b1e076dbcb761524022bf077eb1457b59e38e5c
child 370590 55ba058cf6579ad75fc30b92a9ccb93414078140
child 370591 5a56bb302a66213ba8ce6d0b06c5b99e76a1dcc0
child 370756 0250c99c1033bf562be38f1e38aaf2b1baa484a2
child 370757 303a9765749723a5a503a6b1b32601af576ad131
child 371164 91904d48f96974b9bb41dda61fa34d2c3ffeee93
child 371165 896c822e617ad9f766dfd745852eddff0d07431c
child 371166 b1dac0be1adcd3020687d0ab37c91c7f67c4b433
child 371918 11a987ae5ca75b45e923610e39a53af25e03c5d5
push id18985
push userbmo:gasolin@mozilla.com
push dateTue, 24 May 2016 05:55:47 +0000
reviewersnalexander
bugs1270870
milestone49.0a1
Bug 1270870 - Check profile when delivering pending push message; r=nalexander For pending push messages, we used to check for correct profile when the message is received, but it's better to check for correct profile when the message is delivered to Gecko. This fixes a crash in headless mode that the previous patches introduced.
mobile/android/base/java/org/mozilla/gecko/push/PushService.java
--- a/mobile/android/base/java/org/mozilla/gecko/push/PushService.java
+++ b/mobile/android/base/java/org/mozilla/gecko/push/PushService.java
@@ -83,27 +83,27 @@ public class PushService implements Bund
         sInstance.registerGeckoEventListener();
         sInstance.onStartup();
     }
 
     protected final PushManager pushManager;
 
     private boolean canSendPushMessagesToGecko;
 
-    private final List<String> pendingPushMessages;
+    private final List<JSONObject> pendingPushMessages;
 
     public PushService(Context context) {
         pushManager = new PushManager(new PushState(context, "GeckoPushState.json"), new GcmTokenClient(context), new PushManager.PushClientFactory() {
             @Override
             public PushClient getPushClient(String autopushEndpoint, boolean debug) {
                 return new PushClient(autopushEndpoint);
             }
         });
 
-        pendingPushMessages = new LinkedList<String>();
+        pendingPushMessages = new LinkedList<>();
     }
 
     public void onStartup() {
         Log.i(LOG_TAG, "Starting up.");
         ThreadUtils.assertOnBackgroundThread();
 
         try {
             pushManager.startup(System.currentTimeMillis());
@@ -162,62 +162,63 @@ public class PushService implements Bund
 
             final String profileName = subscription.serviceData.optString("profileName", null);
             final String profilePath = subscription.serviceData.optString("profilePath", null);
             if (profileName == null || profilePath == null) {
                 Log.e(LOG_TAG, "Corrupt serviceData found for chid: " + chid + "; ignoring dom/push message.");
                 return;
             }
 
-            final File profileDir = new File(profilePath);
-            if (!GeckoThread.canUseProfile(profileName, profileDir)) {
-                Log.e(LOG_TAG, "Mismatched profile for chid: " + chid + "; ignoring dom/push message.");
-                return;
-            }
-
-            if (!canSendPushMessagesToGecko) {
+            if (canSendPushMessagesToGecko) {
+                if (!GeckoThread.canUseProfile(profileName, new File(profilePath))) {
+                    Log.e(LOG_TAG, "Mismatched profile for chid: " + chid + "; ignoring dom/push message.");
+                    return;
+                }
+            } else {
                 final Intent intent = GeckoService.getIntentToCreateServices(context, "android-push-service");
                 GeckoService.setIntentProfile(intent, profileName, profilePath);
                 context.startService(intent);
             }
 
             // DELIVERANCE!
             final JSONObject data = new JSONObject();
             try {
                 data.put("channelID", chid);
                 data.put("con", bundle.getString("con"));
                 data.put("enc", bundle.getString("enc"));
                 // Only one of cryptokey (newer) and enckey (deprecated) should be set, but the
                 // Gecko handler will verify this.
                 data.put("cryptokey", bundle.getString("cryptokey"));
                 data.put("enckey", bundle.getString("enckey"));
                 data.put("message", bundle.getString("body"));
+
+                if (!canSendPushMessagesToGecko) {
+                    data.put("profileName", profileName);
+                    data.put("profilePath", profilePath);
+                }
             } catch (JSONException e) {
                 Log.e(LOG_TAG, "Got exception delivering dom/push message to Gecko!", e);
                 return;
             }
 
-            enqueueOrSendMessage(data.toString());
+            if (canSendPushMessagesToGecko) {
+                sendMessageToGeckoService(data);
+            } else {
+                Log.i(LOG_TAG, "Service not initialized, adding message to queue.");
+                pendingPushMessages.add(data);
+            }
         } else {
             Log.e(LOG_TAG, "Message directed to unknown service; dropping: " + subscription.service);
         }
     }
 
-    protected void enqueueOrSendMessage(final @NonNull String message) {
-        if (canSendPushMessagesToGecko) {
-            sendMessageToGeckoService(message);
-        } else {
-            Log.i(LOG_TAG, "Service not initialized, adding message to queue.");
-            pendingPushMessages.add(message);
-        }
-    }
-
-    protected void sendMessageToGeckoService(final @NonNull String message) {
+    protected void sendMessageToGeckoService(final @NonNull JSONObject message) {
         Log.i(LOG_TAG, "Delivering dom/push message to Gecko!");
-        GeckoAppShell.notifyObservers("PushServiceAndroidGCM:ReceivedPushMessage", message,
+        GeckoAppShell.notifyObservers("PushServiceAndroidGCM:ReceivedPushMessage",
+                                      message.toString(),
                                       GeckoThread.State.PROFILE_READY);
     }
 
     protected void registerGeckoEventListener() {
         Log.d(LOG_TAG, "Registered Gecko event listener.");
         EventDispatcher.getInstance().registerBackgroundThreadListener(this, GECKO_EVENTS);
     }
 
@@ -274,17 +275,26 @@ public class PushService implements Bund
                 return;
             }
             if ("PushServiceAndroidGCM:Initialized".equals(event)) {
                 // Send all pending messages to Gecko and set the
                 // canSendPushMessageToGecko flag to true so that
                 // all new push messages are sent directly to Gecko
                 // instead of being queued.
                 canSendPushMessagesToGecko = true;
-                for (String pushMessage : pendingPushMessages) {
+                for (JSONObject pushMessage : pendingPushMessages) {
+                    final String profileName = pushMessage.optString("profileName", null);
+                    final String profilePath = pushMessage.optString("profilePath", null);
+                    if (profileName == null || profilePath == null ||
+                            !GeckoThread.canUseProfile(profileName, new File(profilePath))) {
+                        Log.e(LOG_TAG, "Mismatched profile for chid: " +
+                                       pushMessage.optString("channelID") +
+                                       "; ignoring dom/push message.");
+                        continue;
+                    }
                     sendMessageToGeckoService(pushMessage);
                 }
                 pendingPushMessages.clear();
                 callback.sendSuccess(null);
                 return;
             }
             if ("PushServiceAndroidGCM:Uninitialized".equals(event)) {
                 canSendPushMessagesToGecko = false;