Apply new duplication detection logic for M-Notification.ind am: 77a839f1ef am: cf5dcfef5a

am: a22a68f41f

Change-Id: I98fd90d012c6a464d36b7c1ff4c754ed827de504
This commit is contained in:
Taesu Lee
2019-06-21 12:27:38 -07:00
committed by android-build-merger
4 changed files with 43 additions and 59 deletions
@@ -82,6 +82,7 @@ public class DownloadMmsAction extends Action implements Parcelable {
private static final String KEY_SUB_PHONE_NUMBER = "sub_phone_number"; private static final String KEY_SUB_PHONE_NUMBER = "sub_phone_number";
private static final String KEY_AUTO_DOWNLOAD = "auto_download"; private static final String KEY_AUTO_DOWNLOAD = "auto_download";
private static final String KEY_FAILURE_STATUS = "failure_status"; private static final String KEY_FAILURE_STATUS = "failure_status";
private static final String KEY_EXPIRY = "expiry";
// Values we attach to the pending intent that's fired when the message is downloaded. // Values we attach to the pending intent that's fired when the message is downloaded.
// Only applicable when downloading via the platform APIs on L+. // Only applicable when downloading via the platform APIs on L+.
@@ -97,6 +98,7 @@ public class DownloadMmsAction extends Action implements Parcelable {
public static final String EXTRA_CONVERSATION_ID = "conversation_id"; public static final String EXTRA_CONVERSATION_ID = "conversation_id";
public static final String EXTRA_PARTICIPANT_ID = "participant_id"; public static final String EXTRA_PARTICIPANT_ID = "participant_id";
public static final String EXTRA_STATUS_IF_FAILED = "status_if_failed"; public static final String EXTRA_STATUS_IF_FAILED = "status_if_failed";
public static final String EXTRA_EXPIRY = "expiry";
private DownloadMmsAction() { private DownloadMmsAction() {
super(); super();
@@ -130,6 +132,7 @@ public class DownloadMmsAction extends Action implements Parcelable {
actionParameters.putString(KEY_TRANSACTION_ID, message.getMmsTransactionId()); actionParameters.putString(KEY_TRANSACTION_ID, message.getMmsTransactionId());
actionParameters.putParcelable(KEY_NOTIFICATION_URI, notificationUri); actionParameters.putParcelable(KEY_NOTIFICATION_URI, notificationUri);
actionParameters.putBoolean(KEY_AUTO_DOWNLOAD, isAutoDownload(status)); actionParameters.putBoolean(KEY_AUTO_DOWNLOAD, isAutoDownload(status));
actionParameters.putLong(KEY_EXPIRY, message.getMmsExpiry());
final long now = System.currentTimeMillis(); final long now = System.currentTimeMillis();
if (message.getInDownloadWindow(now)) { if (message.getInDownloadWindow(now)) {
@@ -239,6 +242,7 @@ public class DownloadMmsAction extends Action implements Parcelable {
final String conversationId = actionParameters.getString(KEY_CONVERSATION_ID); final String conversationId = actionParameters.getString(KEY_CONVERSATION_ID);
final String participantId = actionParameters.getString(KEY_PARTICIPANT_ID); final String participantId = actionParameters.getString(KEY_PARTICIPANT_ID);
final int statusIfFailed = actionParameters.getInt(KEY_FAILURE_STATUS); final int statusIfFailed = actionParameters.getInt(KEY_FAILURE_STATUS);
final long expiry = actionParameters.getLong(KEY_EXPIRY);
final long receivedTimestampRoundedToSecond = final long receivedTimestampRoundedToSecond =
1000 * ((System.currentTimeMillis() + 500) / 1000); 1000 * ((System.currentTimeMillis() + 500) / 1000);
@@ -256,7 +260,7 @@ public class DownloadMmsAction extends Action implements Parcelable {
// Start the download // Start the download
final MmsUtils.StatusPlusUri status = MmsUtils.downloadMmsMessage(context, final MmsUtils.StatusPlusUri status = MmsUtils.downloadMmsMessage(context,
notificationUri, subId, subPhoneNumber, transactionId, contentLocation, notificationUri, subId, subPhoneNumber, transactionId, contentLocation,
autoDownload, receivedTimestampRoundedToSecond / 1000L, extras); autoDownload, receivedTimestampRoundedToSecond / 1000L, expiry / 1000L, extras);
if (status == MmsUtils.STATUS_PENDING) { if (status == MmsUtils.STATUS_PENDING) {
// Async download; no status yet // Async download; no status yet
if (LogUtil.isLoggable(TAG, LogUtil.DEBUG)) { if (LogUtil.isLoggable(TAG, LogUtil.DEBUG)) {
@@ -78,6 +78,7 @@ public class ProcessDownloadedMmsAction extends Action {
private static final String KEY_CONTENT_LOCATION = "content_location"; private static final String KEY_CONTENT_LOCATION = "content_location";
private static final String KEY_AUTO_DOWNLOAD = "auto_download"; private static final String KEY_AUTO_DOWNLOAD = "auto_download";
private static final String KEY_RECEIVED_TIMESTAMP = "received_timestamp"; private static final String KEY_RECEIVED_TIMESTAMP = "received_timestamp";
private static final String KEY_EXPIRY = "expiry";
// Set when message downloaded by us (legacy) // Set when message downloaded by us (legacy)
private static final String KEY_STATUS = "status"; private static final String KEY_STATUS = "status";
@@ -130,6 +131,7 @@ public class ProcessDownloadedMmsAction extends Action {
params.putString(KEY_PARTICIPANT_ID, participantId); params.putString(KEY_PARTICIPANT_ID, participantId);
params.putInt(KEY_STATUS_IF_FAILED, params.putInt(KEY_STATUS_IF_FAILED,
extras.getInt(DownloadMmsAction.EXTRA_STATUS_IF_FAILED)); extras.getInt(DownloadMmsAction.EXTRA_STATUS_IF_FAILED));
params.putLong(KEY_EXPIRY, extras.getLong(DownloadMmsAction.EXTRA_EXPIRY));
action.start(); action.start();
} }
@@ -279,6 +281,7 @@ public class ProcessDownloadedMmsAction extends Action {
KEY_AUTO_DOWNLOAD); KEY_AUTO_DOWNLOAD);
final long receivedTimestampInSeconds = final long receivedTimestampInSeconds =
actionParameters.getLong(KEY_RECEIVED_TIMESTAMP); actionParameters.getLong(KEY_RECEIVED_TIMESTAMP);
final long expiry = actionParameters.getLong(KEY_EXPIRY);
// Inform sync we're adding a message to telephony // Inform sync we're adding a message to telephony
final SyncManager syncManager = DataModel.get().getSyncManager(); final SyncManager syncManager = DataModel.get().getSyncManager();
@@ -288,7 +291,7 @@ public class ProcessDownloadedMmsAction extends Action {
MmsUtils.insertDownloadedMessageAndSendResponse(context, MmsUtils.insertDownloadedMessageAndSendResponse(context,
notificationUri, subId, subPhoneNumber, transactionId, notificationUri, subId, subPhoneNumber, transactionId,
contentLocation, autoDownload, receivedTimestampInSeconds, contentLocation, autoDownload, receivedTimestampInSeconds,
retrieveConf); expiry, retrieveConf);
status = result.status; status = result.status;
rawStatus = result.rawStatus; rawStatus = result.rawStatus;
mmsUri = result.uri; mmsUri = result.uri;
@@ -540,6 +540,10 @@ public class MessageData implements Parcelable {
return mSeen; return mSeen;
} }
public final long getMmsExpiry() {
return mMmsExpiry;
}
/** /**
* For incoming MMS messages this returns the retrieve-status value * For incoming MMS messages this returns the retrieve-status value
* For sent MMS messages this returns the response-status value * For sent MMS messages this returns the response-status value
+30 -57
View File
@@ -952,7 +952,7 @@ public class MmsUtils {
// Persist a received MMS message in telephony // Persist a received MMS message in telephony
public static Uri insertReceivedMmsMessage(final Context context, public static Uri insertReceivedMmsMessage(final Context context,
final RetrieveConf retrieveConf, final int subId, final String subPhoneNumber, final RetrieveConf retrieveConf, final int subId, final String subPhoneNumber,
final long receivedTimestampInSeconds, final String contentLocation) { final long receivedTimestampInSeconds, final long expiry, final String transactionId) {
final PduPersister persister = PduPersister.getPduPersister(context); final PduPersister persister = PduPersister.getPduPersister(context);
Uri uri = null; Uri uri = null;
try { try {
@@ -963,12 +963,13 @@ public class MmsUtils {
subPhoneNumber, subPhoneNumber,
null/*preOpenedFiles*/); null/*preOpenedFiles*/);
final ContentValues values = new ContentValues(2); final ContentValues values = new ContentValues(3);
// Update mms table with local time instead of PDU time // Update mms table with local time instead of PDU time
values.put(Mms.DATE, receivedTimestampInSeconds); values.put(Mms.DATE, receivedTimestampInSeconds);
// Also update the content location field from NotificationInd so that // Also update the transaction id and the expiry from NotificationInd so that
// wap push dedup would work even after the wap push is deleted // wap push dedup would work even after the wap push is deleted.
values.put(Mms.CONTENT_LOCATION, contentLocation); values.put(Mms.TRANSACTION_ID, transactionId);
values.put(Mms.EXPIRY, expiry);
SqliteWrapper.update(context, context.getContentResolver(), uri, values, null, null); SqliteWrapper.update(context, context.getContentResolver(), uri, values, null, null);
if (LogUtil.isLoggable(TAG, LogUtil.DEBUG)) { if (LogUtil.isLoggable(TAG, LogUtil.DEBUG)) {
LogUtil.d(TAG, "MmsUtils: Inserted MMS message into telephony, uri: " + uri); LogUtil.d(TAG, "MmsUtils: Inserted MMS message into telephony, uri: " + uri);
@@ -1843,7 +1844,7 @@ public class MmsUtils {
public static StatusPlusUri downloadMmsMessage(final Context context, final Uri notificationUri, public static StatusPlusUri downloadMmsMessage(final Context context, final Uri notificationUri,
final int subId, final String subPhoneNumber, final String transactionId, final int subId, final String subPhoneNumber, final String transactionId,
final String contentLocation, final boolean autoDownload, final String contentLocation, final boolean autoDownload,
final long receivedTimestampInSeconds, Bundle extras) { final long receivedTimestampInSeconds, final long expiry, Bundle extras) {
if (TextUtils.isEmpty(contentLocation)) { if (TextUtils.isEmpty(contentLocation)) {
LogUtil.e(TAG, "MmsUtils: Download from empty content location URL"); LogUtil.e(TAG, "MmsUtils: Download from empty content location URL");
return new StatusPlusUri( return new StatusPlusUri(
@@ -1894,13 +1895,14 @@ public class MmsUtils {
extras.putBoolean(DownloadMmsAction.EXTRA_AUTO_DOWNLOAD, autoDownload); extras.putBoolean(DownloadMmsAction.EXTRA_AUTO_DOWNLOAD, autoDownload);
extras.putLong(DownloadMmsAction.EXTRA_RECEIVED_TIMESTAMP, extras.putLong(DownloadMmsAction.EXTRA_RECEIVED_TIMESTAMP,
receivedTimestampInSeconds); receivedTimestampInSeconds);
extras.putLong(DownloadMmsAction.EXTRA_EXPIRY, expiry);
MmsSender.downloadMms(context, subId, contentLocation, extras); MmsSender.downloadMms(context, subId, contentLocation, extras);
return STATUS_PENDING; // Download happens asynchronously; no status to return return STATUS_PENDING; // Download happens asynchronously; no status to return
} }
return insertDownloadedMessageAndSendResponse(context, notificationUri, subId, return insertDownloadedMessageAndSendResponse(context, notificationUri, subId,
subPhoneNumber, transactionId, contentLocation, autoDownload, subPhoneNumber, transactionId, contentLocation, autoDownload,
receivedTimestampInSeconds, retrieveConf); receivedTimestampInSeconds, expiry, retrieveConf);
} catch (final MmsFailureException e) { } catch (final MmsFailureException e) {
LogUtil.e(TAG, "MmsUtils: failed to download message " + notificationUri, e); LogUtil.e(TAG, "MmsUtils: failed to download message " + notificationUri, e);
@@ -1915,7 +1917,7 @@ public class MmsUtils {
final Uri notificationUri, final int subId, final String subPhoneNumber, final Uri notificationUri, final int subId, final String subPhoneNumber,
final String transactionId, final String contentLocation, final String transactionId, final String contentLocation,
final boolean autoDownload, final long receivedTimestampInSeconds, final boolean autoDownload, final long receivedTimestampInSeconds,
final RetrieveConf retrieveConf) { final long expiry, final RetrieveConf retrieveConf) {
final byte[] notificationTransactionId = stringToBytes(transactionId, "UTF-8"); final byte[] notificationTransactionId = stringToBytes(transactionId, "UTF-8");
Uri messageUri = null; Uri messageUri = null;
int status = MMS_REQUEST_MANUAL_RETRY; int status = MMS_REQUEST_MANUAL_RETRY;
@@ -1954,7 +1956,7 @@ public class MmsUtils {
// Insert downloaded message into telephony // Insert downloaded message into telephony
final Uri inboxUri = MmsUtils.insertReceivedMmsMessage(context, retrieveConf, subId, final Uri inboxUri = MmsUtils.insertReceivedMmsMessage(context, retrieveConf, subId,
subPhoneNumber, receivedTimestampInSeconds, contentLocation); subPhoneNumber, receivedTimestampInSeconds, expiry, transactionId);
messageUri = ContentUris.withAppendedId(Mms.CONTENT_URI, ContentUris.parseId(inboxUri)); messageUri = ContentUris.withAppendedId(Mms.CONTENT_URI, ContentUris.parseId(inboxUri));
} else if (status == MMS_REQUEST_AUTO_RETRY) { } else if (status == MMS_REQUEST_AUTO_RETRY) {
// For a retry do nothing // For a retry do nothing
@@ -2171,57 +2173,28 @@ public class MmsUtils {
uri, values, null, null); uri, values, null, null);
} }
// Selection for new dedup algorithm: // Selection for dedup algorithm:
// ((m_type<>130) OR (exp>NOW)) AND (date>NOW-7d) AND (date<NOW+7d) AND (ct_l=xxxxxx) // ((m_type=NOTIFICATION_IND) OR (m_type=RETRIEVE_CONF)) AND (exp>NOW)) AND (t_id=xxxxxx)
// i.e. If it is NotificationInd and not expired or not NotificationInd // i.e. If it is NotificationInd or RetrieveConf and not expired
// AND message is received with +/- 7 days from now // AND transaction id is the input id
// AND content location is the input URL
private static final String DUP_NOTIFICATION_QUERY_SELECTION = private static final String DUP_NOTIFICATION_QUERY_SELECTION =
"((" + Mms.MESSAGE_TYPE + "<>?) OR (" + Mms.EXPIRY + ">?)) AND (" "((" + Mms.MESSAGE_TYPE + "=?) OR (" + Mms.MESSAGE_TYPE + "=?)) AND ("
+ Mms.DATE + ">?) AND (" + Mms.DATE + "<?) AND (" + Mms.CONTENT_LOCATION + + Mms.EXPIRY + ">?) AND (" + Mms.TRANSACTION_ID + "=?)";
"=?)";
// Selection for old behavior: only checks NotificationInd and its content location
private static final String DUP_NOTIFICATION_QUERY_SELECTION_OLD =
"(" + Mms.MESSAGE_TYPE + "=?) AND (" + Mms.CONTENT_LOCATION + "=?)";
private static final int MAX_RETURN = 32; private static final int MAX_RETURN = 32;
private static String[] getDupNotifications(final Context context, final NotificationInd nInd) { private static String[] getDupNotifications(final Context context, final NotificationInd nInd) {
final byte[] rawLocation = nInd.getContentLocation(); final byte[] rawTransactionId = nInd.getTransactionId();
if (rawLocation != null) { if (rawTransactionId != null) {
final String location = new String(rawLocation); // dedup algorithm
// We can not be sure if the content location of an MMS is globally and historically String selection = DUP_NOTIFICATION_QUERY_SELECTION;
// unique. So we limit the dedup time within the last 7 days final long nowSecs = System.currentTimeMillis() / 1000;
// (or configured by gservices remotely). If the same content location shows up after String[] selectionArgs = new String[] {
// that, we will download regardless. Duplicated message is better than no message. Integer.toString(PduHeaders.MESSAGE_TYPE_NOTIFICATION_IND),
String selection; Integer.toString(PduHeaders.MESSAGE_TYPE_RETRIEVE_CONF),
String[] selectionArgs; Long.toString(nowSecs),
final long timeLimit = BugleGservices.get().getLong( new String(rawTransactionId)
BugleGservicesKeys.MMS_WAP_PUSH_DEDUP_TIME_LIMIT_SECS, };
BugleGservicesKeys.MMS_WAP_PUSH_DEDUP_TIME_LIMIT_SECS_DEFAULT);
if (timeLimit > 0) {
// New dedup algorithm
selection = DUP_NOTIFICATION_QUERY_SELECTION;
final long nowSecs = System.currentTimeMillis() / 1000;
final long timeLowerBoundSecs = nowSecs - timeLimit;
// Need upper bound to protect against clock change so that a message has a time
// stamp in the future
final long timeUpperBoundSecs = nowSecs + timeLimit;
selectionArgs = new String[] {
Integer.toString(PduHeaders.MESSAGE_TYPE_NOTIFICATION_IND),
Long.toString(nowSecs),
Long.toString(timeLowerBoundSecs),
Long.toString(timeUpperBoundSecs),
location
};
} else {
// If time limit is 0, we revert back to old behavior in case the new
// dedup algorithm behaves badly
selection = DUP_NOTIFICATION_QUERY_SELECTION_OLD;
selectionArgs = new String[] {
Integer.toString(PduHeaders.MESSAGE_TYPE_NOTIFICATION_IND),
location
};
}
Cursor cursor = null; Cursor cursor = null;
try { try {
cursor = SqliteWrapper.query( cursor = SqliteWrapper.query(
@@ -2358,7 +2331,7 @@ public class MmsUtils {
} else { } else {
LogUtil.w(TAG, "Received WAP Push is a dup: " + Joiner.on(',').join(dups)); LogUtil.w(TAG, "Received WAP Push is a dup: " + Joiner.on(',').join(dups));
if (LogUtil.isLoggable(TAG, LogUtil.VERBOSE)) { if (LogUtil.isLoggable(TAG, LogUtil.VERBOSE)) {
LogUtil.w(TAG, "Dup WAP Push url=" + new String(nInd.getContentLocation())); LogUtil.w(TAG, "Dup Transaction Id=" + new String(nInd.getTransactionId()));
} }
} }
break; break;