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.app.job.JobInfo; |
| 8 import android.app.job.JobScheduler; |
| 9 import android.content.ComponentName; |
| 10 import android.content.Context; |
| 11 import android.os.Build; |
7 import android.os.Bundle; | 12 import android.os.Bundle; |
8 import android.text.TextUtils; | 13 import android.text.TextUtils; |
9 | 14 |
10 import com.google.android.gms.gcm.GcmListenerService; | 15 import com.google.android.gms.gcm.GcmListenerService; |
11 import com.google.ipc.invalidation.ticl.android2.channel.AndroidGcmController; | 16 import com.google.ipc.invalidation.ticl.android2.channel.AndroidGcmController; |
12 | 17 |
13 import org.chromium.base.Log; | 18 import org.chromium.base.Log; |
14 import org.chromium.base.ThreadUtils; | 19 import org.chromium.base.ThreadUtils; |
15 import org.chromium.base.annotations.SuppressFBWarnings; | 20 import org.chromium.base.annotations.SuppressFBWarnings; |
16 import org.chromium.base.library_loader.ProcessInitException; | 21 import org.chromium.base.library_loader.ProcessInitException; |
| 22 import org.chromium.chrome.browser.JobSchedulerConstants; |
17 import org.chromium.chrome.browser.init.ChromeBrowserInitializer; | 23 import org.chromium.chrome.browser.init.ChromeBrowserInitializer; |
18 import org.chromium.chrome.browser.init.ProcessInitializationHandler; | 24 import org.chromium.chrome.browser.init.ProcessInitializationHandler; |
19 import org.chromium.components.gcm_driver.GCMDriver; | 25 import org.chromium.components.gcm_driver.GCMDriver; |
| 26 import org.chromium.components.gcm_driver.GCMMessage; |
20 | 27 |
21 /** | 28 /** |
22 * Receives Downstream messages and status of upstream messages from GCM. | 29 * Receives Downstream messages and status of upstream messages from GCM. |
23 */ | 30 */ |
24 public class ChromeGcmListenerService extends GcmListenerService { | 31 public class ChromeGcmListenerService extends GcmListenerService { |
25 private static final String TAG = "ChromeGcmListener"; | 32 private static final String TAG = "ChromeGcmListener"; |
26 | 33 |
27 @Override | 34 @Override |
28 public void onCreate() { | 35 public void onCreate() { |
29 ProcessInitializationHandler.getInstance().initializePreNative(); | 36 ProcessInitializationHandler.getInstance().initializePreNative(); |
30 super.onCreate(); | 37 super.onCreate(); |
31 } | 38 } |
32 | 39 |
33 @Override | 40 @Override |
34 public void onMessageReceived(String from, Bundle data) { | 41 public void onMessageReceived(String from, Bundle data) { |
35 boolean hasCollapseKey = !TextUtils.isEmpty(data.getString("collapse_key
")); | 42 boolean hasCollapseKey = !TextUtils.isEmpty(data.getString("collapse_key
")); |
36 GcmUma.recordDataMessageReceived(getApplicationContext(), hasCollapseKey
); | 43 GcmUma.recordDataMessageReceived(getApplicationContext(), hasCollapseKey
); |
37 | 44 |
38 String invalidationSenderId = AndroidGcmController.get(this).getSenderId
(); | 45 String invalidationSenderId = AndroidGcmController.get(this).getSenderId
(); |
39 if (from.equals(invalidationSenderId)) { | 46 if (from.equals(invalidationSenderId)) { |
40 AndroidGcmController.get(this).onMessageReceived(data); | 47 AndroidGcmController.get(this).onMessageReceived(data); |
41 return; | 48 return; |
42 } | 49 } |
43 pushMessageReceived(from, data); | 50 |
| 51 GCMMessage message = null; |
| 52 try { |
| 53 message = new GCMMessage(from, data); |
| 54 } catch (IllegalArgumentException e) { |
| 55 Log.e(TAG, "Received an invalid GCM Message", e); |
| 56 return; |
| 57 } |
| 58 |
| 59 // Dispatch the message to the GCM Driver for native features. |
| 60 scheduleOrDispatchMessageToDriver(getApplicationContext(), message); |
44 } | 61 } |
45 | 62 |
46 @Override | 63 @Override |
47 public void onMessageSent(String msgId) { | 64 public void onMessageSent(String msgId) { |
48 Log.d(TAG, "Message sent successfully. Message id: " + msgId); | 65 Log.d(TAG, "Message sent successfully. Message id: " + msgId); |
49 GcmUma.recordGcmUpstreamHistogram(getApplicationContext(), GcmUma.UMA_UP
STREAM_SUCCESS); | 66 GcmUma.recordGcmUpstreamHistogram(getApplicationContext(), GcmUma.UMA_UP
STREAM_SUCCESS); |
50 } | 67 } |
51 | 68 |
52 @Override | 69 @Override |
53 public void onSendError(String msgId, String error) { | 70 public void onSendError(String msgId, String error) { |
54 Log.w(TAG, "Error in sending message. Message id: " + msgId + " Error: "
+ error); | 71 Log.w(TAG, "Error in sending message. Message id: " + msgId + " Error: "
+ error); |
55 GcmUma.recordGcmUpstreamHistogram(getApplicationContext(), GcmUma.UMA_UP
STREAM_SEND_FAILED); | 72 GcmUma.recordGcmUpstreamHistogram(getApplicationContext(), GcmUma.UMA_UP
STREAM_SEND_FAILED); |
56 } | 73 } |
57 | 74 |
58 @Override | 75 @Override |
59 public void onDeletedMessages() { | 76 public void onDeletedMessages() { |
60 // TODO(johnme): Ask GCM to include the subtype in this event. | 77 // 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" | 78 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."); | 79 + "know what subtype (app ID) it occurred for."); |
63 GcmUma.recordDeletedMessages(getApplicationContext()); | 80 GcmUma.recordDeletedMessages(getApplicationContext()); |
64 } | 81 } |
65 | 82 |
66 private void pushMessageReceived(final String from, final Bundle data) { | 83 /** |
67 final String bundleSubtype = "subtype"; | 84 * Either schedules |message| to be dispatched through the Job Scheduler, wh
ich we use on |
68 if (!data.containsKey(bundleSubtype)) { | 85 * 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"); | 86 */ |
70 return; | 87 static void scheduleOrDispatchMessageToDriver(final Context context, final G
CMMessage message) { |
| 88 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { |
| 89 // TODO(peter): Add UMA for measuring latency introduced by the JobS
cheduler. |
| 90 JobInfo job = new JobInfo |
| 91 .Builder(JobSchedulerConstants.GCM_DRIVER_JOB_
ID, |
| 92 new ComponentName(context, GCMJobServi
ce.class)) |
| 93 .setExtras(message.toPersistableBundle()) |
| 94 .setOverrideDeadline(0) |
| 95 .build(); |
| 96 JobScheduler scheduler = |
| 97 (JobScheduler) context.getSystemService(Context.JOB_SCHEDULE
R_SERVICE); |
| 98 scheduler.schedule(job); |
| 99 } else { |
| 100 ThreadUtils.runOnUiThread(new Runnable() { |
| 101 @Override |
| 102 public void run() { |
| 103 ChromeGcmListenerService.dispatchMessageToDriver(context, me
ssage); |
| 104 } |
| 105 }); |
71 } | 106 } |
72 final String appId = data.getString(bundleSubtype); | 107 } |
73 ThreadUtils.runOnUiThread(new Runnable() { | 108 |
74 @Override | 109 /** |
75 @SuppressFBWarnings("DM_EXIT") | 110 * To be called when a GCM message is ready to be dispatched. Will initialis
e the native code |
76 public void run() { | 111 * of the browser process, and forward the message to the GCM Driver. Must b
e called on the UI |
77 try { | 112 * thread. |
78 ChromeBrowserInitializer.getInstance(getApplicationContext()
) | 113 */ |
79 .handleSynchronousStartup(); | 114 @SuppressFBWarnings("DM_EXIT") |
80 GCMDriver.onMessageReceived(appId, from, data); | 115 static void dispatchMessageToDriver(Context applicationContext, GCMMessage m
essage) { |
81 } catch (ProcessInitException e) { | 116 ThreadUtils.assertOnUiThread(); |
82 Log.e(TAG, "ProcessInitException while starting the browser
process"); | 117 |
83 // Since the library failed to initialize nothing in the app
lication | 118 try { |
84 // can work, so kill the whole application not just the acti
vity. | 119 ChromeBrowserInitializer.getInstance(applicationContext).handleSynch
ronousStartup(); |
85 System.exit(-1); | 120 GCMDriver.dispatchMessage(message); |
86 } | 121 |
87 } | 122 } catch (ProcessInitException e) { |
88 }); | 123 Log.e(TAG, "ProcessInitException while starting the browser process"
); |
| 124 |
| 125 // Since the library failed to initialize nothing in the application
can work, so kill |
| 126 // the whole application as opposed to just this service. |
| 127 System.exit(-1); |
| 128 } |
89 } | 129 } |
90 } | 130 } |
OLD | NEW |