OLD | NEW |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 package org.chromium.chrome.browser.services.gcm; | 5 package org.chromium.chrome.browser.services.gcm; |
6 | 6 |
| 7 import android.content.Context; |
| 8 import android.os.Build; |
7 import android.os.Bundle; | 9 import android.os.Bundle; |
8 import android.text.TextUtils; | 10 import android.text.TextUtils; |
9 | 11 |
10 import com.google.android.gms.gcm.GcmListenerService; | 12 import com.google.android.gms.gcm.GcmListenerService; |
11 import com.google.ipc.invalidation.ticl.android2.channel.AndroidGcmController; | 13 import com.google.ipc.invalidation.ticl.android2.channel.AndroidGcmController; |
12 | 14 |
13 import org.chromium.base.Log; | 15 import org.chromium.base.Log; |
14 import org.chromium.base.ThreadUtils; | 16 import org.chromium.base.ThreadUtils; |
15 import org.chromium.base.annotations.SuppressFBWarnings; | 17 import org.chromium.base.annotations.SuppressFBWarnings; |
16 import org.chromium.base.library_loader.ProcessInitException; | 18 import org.chromium.base.library_loader.ProcessInitException; |
17 import org.chromium.chrome.browser.init.ChromeBrowserInitializer; | 19 import org.chromium.chrome.browser.init.ChromeBrowserInitializer; |
18 import org.chromium.chrome.browser.init.ProcessInitializationHandler; | 20 import org.chromium.chrome.browser.init.ProcessInitializationHandler; |
| 21 import org.chromium.components.background_task_scheduler.BackgroundTaskScheduler
Factory; |
| 22 import org.chromium.components.background_task_scheduler.TaskIds; |
| 23 import org.chromium.components.background_task_scheduler.TaskInfo; |
19 import org.chromium.components.gcm_driver.GCMDriver; | 24 import org.chromium.components.gcm_driver.GCMDriver; |
| 25 import org.chromium.components.gcm_driver.GCMMessage; |
20 | 26 |
21 /** | 27 /** |
22 * Receives Downstream messages and status of upstream messages from GCM. | 28 * Receives Downstream messages and status of upstream messages from GCM. |
23 */ | 29 */ |
24 public class ChromeGcmListenerService extends GcmListenerService { | 30 public class ChromeGcmListenerService extends GcmListenerService { |
25 private static final String TAG = "ChromeGcmListener"; | 31 private static final String TAG = "ChromeGcmListener"; |
26 | 32 |
27 @Override | 33 @Override |
28 public void onCreate() { | 34 public void onCreate() { |
29 ProcessInitializationHandler.getInstance().initializePreNative(); | 35 ProcessInitializationHandler.getInstance().initializePreNative(); |
30 super.onCreate(); | 36 super.onCreate(); |
31 } | 37 } |
32 | 38 |
33 @Override | 39 @Override |
34 public void onMessageReceived(String from, Bundle data) { | 40 public void onMessageReceived(final String from, final Bundle data) { |
35 boolean hasCollapseKey = !TextUtils.isEmpty(data.getString("collapse_key
")); | 41 boolean hasCollapseKey = !TextUtils.isEmpty(data.getString("collapse_key
")); |
36 GcmUma.recordDataMessageReceived(getApplicationContext(), hasCollapseKey
); | 42 GcmUma.recordDataMessageReceived(getApplicationContext(), hasCollapseKey
); |
37 | 43 |
38 String invalidationSenderId = AndroidGcmController.get(this).getSenderId
(); | 44 String invalidationSenderId = AndroidGcmController.get(this).getSenderId
(); |
39 if (from.equals(invalidationSenderId)) { | 45 if (from.equals(invalidationSenderId)) { |
40 AndroidGcmController.get(this).onMessageReceived(data); | 46 AndroidGcmController.get(this).onMessageReceived(data); |
41 return; | 47 return; |
42 } | 48 } |
43 pushMessageReceived(from, data); | 49 |
| 50 final Context applicationContext = getApplicationContext(); |
| 51 |
| 52 // Dispatch the message to the GCM Driver for native features. |
| 53 ThreadUtils.runOnUiThread(new Runnable() { |
| 54 @Override |
| 55 public void run() { |
| 56 GCMMessage message = null; |
| 57 try { |
| 58 message = new GCMMessage(from, data); |
| 59 } catch (IllegalArgumentException e) { |
| 60 Log.e(TAG, "Received an invalid GCM Message", e); |
| 61 return; |
| 62 } |
| 63 |
| 64 scheduleOrDispatchMessageToDriver(applicationContext, message); |
| 65 } |
| 66 }); |
44 } | 67 } |
45 | 68 |
46 @Override | 69 @Override |
47 public void onMessageSent(String msgId) { | 70 public void onMessageSent(String msgId) { |
48 Log.d(TAG, "Message sent successfully. Message id: " + msgId); | 71 Log.d(TAG, "Message sent successfully. Message id: " + msgId); |
49 GcmUma.recordGcmUpstreamHistogram(getApplicationContext(), GcmUma.UMA_UP
STREAM_SUCCESS); | 72 GcmUma.recordGcmUpstreamHistogram(getApplicationContext(), GcmUma.UMA_UP
STREAM_SUCCESS); |
50 } | 73 } |
51 | 74 |
52 @Override | 75 @Override |
53 public void onSendError(String msgId, String error) { | 76 public void onSendError(String msgId, String error) { |
54 Log.w(TAG, "Error in sending message. Message id: " + msgId + " Error: "
+ error); | 77 Log.w(TAG, "Error in sending message. Message id: " + msgId + " Error: "
+ error); |
55 GcmUma.recordGcmUpstreamHistogram(getApplicationContext(), GcmUma.UMA_UP
STREAM_SEND_FAILED); | 78 GcmUma.recordGcmUpstreamHistogram(getApplicationContext(), GcmUma.UMA_UP
STREAM_SEND_FAILED); |
56 } | 79 } |
57 | 80 |
58 @Override | 81 @Override |
59 public void onDeletedMessages() { | 82 public void onDeletedMessages() { |
60 // TODO(johnme): Ask GCM to include the subtype in this event. | 83 // TODO(johnme): Ask GCM to include the subtype in this event. |
61 Log.w(TAG, "Push messages were deleted, but we can't tell the Service Wo
rker as we don't" | 84 Log.w(TAG, "Push messages were deleted, but we can't tell the Service Wo
rker as we don't" |
62 + "know what subtype (app ID) it occurred for."); | 85 + "know what subtype (app ID) it occurred for."); |
63 GcmUma.recordDeletedMessages(getApplicationContext()); | 86 GcmUma.recordDeletedMessages(getApplicationContext()); |
64 } | 87 } |
65 | 88 |
66 private void pushMessageReceived(final String from, final Bundle data) { | 89 /** |
67 final String bundleSubtype = "subtype"; | 90 * Either schedules |message| to be dispatched through the Job Scheduler, wh
ich we use on |
68 if (!data.containsKey(bundleSubtype)) { | 91 * Android N and beyond, or immediately dispatches the message on other vers
ions of Android. |
69 Log.w(TAG, "Received push message with no subtype"); | 92 * Must be called on the UI thread both for the BackgroundTaskScheduler and
for dispatching |
70 return; | 93 * the |message| to the GCMDriver. |
| 94 */ |
| 95 static void scheduleOrDispatchMessageToDriver(Context context, GCMMessage me
ssage) { |
| 96 ThreadUtils.assertOnUiThread(); |
| 97 |
| 98 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { |
| 99 Bundle extras = message.toBundle(); |
| 100 |
| 101 // TODO(peter): Add UMA for measuring latency introduced by the Back
groundTaskScheduler. |
| 102 TaskInfo backgroundTask = TaskInfo.createOneOffTask(TaskIds.GCM_BACK
GROUND_TASK_JOB_ID, |
| 103 GCMBackgroundTask.class, 0
/* immediately */) |
| 104 .setExtras(extras) |
| 105 .build(); |
| 106 |
| 107 BackgroundTaskSchedulerFactory.getScheduler().schedule(context, back
groundTask); |
| 108 |
| 109 } else { |
| 110 dispatchMessageToDriver(context, message); |
71 } | 111 } |
72 final String appId = data.getString(bundleSubtype); | 112 } |
73 ThreadUtils.runOnUiThread(new Runnable() { | 113 |
74 @Override | 114 /** |
75 @SuppressFBWarnings("DM_EXIT") | 115 * To be called when a GCM message is ready to be dispatched. Will initialis
e the native code |
76 public void run() { | 116 * of the browser process, and forward the message to the GCM Driver. Must b
e called on the UI |
77 try { | 117 * thread. |
78 ChromeBrowserInitializer.getInstance(getApplicationContext()
) | 118 */ |
79 .handleSynchronousStartup(); | 119 @SuppressFBWarnings("DM_EXIT") |
80 GCMDriver.onMessageReceived(appId, from, data); | 120 static void dispatchMessageToDriver(Context applicationContext, GCMMessage m
essage) { |
81 } catch (ProcessInitException e) { | 121 ThreadUtils.assertOnUiThread(); |
82 Log.e(TAG, "ProcessInitException while starting the browser
process"); | 122 |
83 // Since the library failed to initialize nothing in the app
lication | 123 try { |
84 // can work, so kill the whole application not just the acti
vity. | 124 ChromeBrowserInitializer.getInstance(applicationContext).handleSynch
ronousStartup(); |
85 System.exit(-1); | 125 GCMDriver.dispatchMessage(message); |
86 } | 126 |
87 } | 127 } catch (ProcessInitException e) { |
88 }); | 128 Log.e(TAG, "ProcessInitException while starting the browser process"
); |
| 129 |
| 130 // Since the library failed to initialize nothing in the application
can work, so kill |
| 131 // the whole application as opposed to just this service. |
| 132 System.exit(-1); |
| 133 } |
89 } | 134 } |
90 } | 135 } |
OLD | NEW |