分析原因:收到短信,sms表插入信息,触发器会自动更新thread表,更新失败导致一直有一条未读信息数量显示,但在会话列表中却看不到。
(偶现,低概率。 解决方法:接收新信息插入后,立即查询thread表,如果刚刚的信息查不到,则再次手动更新)
androidpackagesprovidersTelephonyProvidersrccomandroidproviders elephonyMmsSmsDatabaseHelper.java中定义了触发器
private void createCommonTriggers(SQLiteDatabase db) { // Updates threads table whenever a message is added to sms. db.execSQL("CREATE TRIGGER sms_update_thread_on_insert AFTER INSERT ON sms " + SMS_UPDATE_THREAD_DATE_SNIPPET_COUNT_ON_UPDATE); // Updates threads table whenever a message in sms is updated. db.execSQL("CREATE TRIGGER sms_update_thread_date_subject_on_update AFTER" + " UPDATE OF " + Sms.DATE + ", " + Sms.BODY + ", " + Sms.TYPE + " ON sms " + SMS_UPDATE_THREAD_DATE_SNIPPET_COUNT_ON_UPDATE); // Updates threads table whenever a message in sms is updated. db.execSQL("CREATE TRIGGER sms_update_thread_read_on_update AFTER" + " UPDATE OF " + Sms.READ + " ON sms " + "BEGIN " + SMS_UPDATE_THREAD_READ_BODY + "END;"); // TODO Add triggers for SMS retry-status management. // Update the error flag of threads when the error type of // a pending MM is updated. db.execSQL("CREATE TRIGGER update_threads_error_on_update_mms " + " AFTER UPDATE OF err_type ON pending_msgs " + " WHEN (OLD.err_type < 10 AND NEW.err_type >= 10)" + " OR (OLD.err_type >= 10 AND NEW.err_type < 10) " + "BEGIN" + " UPDATE threads SET error = " + " CASE" + " WHEN NEW.err_type >= 10 THEN error + 1" + " ELSE error - 1" + " END " + " WHERE _id =" + " (SELECT DISTINCT thread_id" + " FROM pdu" + " WHERE _id = NEW.msg_id); " + "END;"); // Update the error flag of threads after a text message was // failed to send/receive. db.execSQL("CREATE TRIGGER update_threads_error_on_update_sms " + " AFTER UPDATE OF type ON sms" + " WHEN (OLD.type != 5 AND NEW.type = 5)" + " OR (OLD.type = 5 AND NEW.type != 5) " + "BEGIN " + " UPDATE threads SET error = " + " CASE" + " WHEN NEW.type = 5 THEN error + 1" + " ELSE error - 1" + " END " + " WHERE _id = NEW.thread_id; " + "END;"); }
Ril层接收新信息会通过Framework发通知——android.provider.Telephony.SMS_DELIVER
APP层MMS开始处理com.android.mms.transaction.PrivilegedSmsReceiver接收广播,
com.android.mms.transaction.SmsReceiverService调用handleSmsReceived(intent, error)方法,
————>saveMessageToPhone(msgs, error, format)————> insertMessage(this, msgs, error, format)
————>storeMessage(context, msgs, error);
storeMessage(context, msgs, error)方法最后,增加查询thread表,确认信息更新是否成功,如果thread表信息更新失败,手动更新.
private Uri storeMessage(Context context, SmsMessage[] msgs, int error) { // Check to see whether short message count is up to 2000 for cmcc if (MessageUtils.checkIsPhoneMessageFull(this)) { return null; } SmsMessage sms = msgs[0]; // Store the message in the content provider. ContentValues values = extractContentValues(sms); values.put(Sms.ERROR_CODE, error); values.put(Sms.PHONE_ID, SubscriptionManager.getPhoneId(sms.getSubId())); int pduCount = msgs.length; if (pduCount == 1) { // There is only one part, so grab the body directly. values.put(Inbox.BODY, replaceFormFeeds(sms.getDisplayMessageBody())); } else { // Build up the body from the parts. StringBuilder body = new StringBuilder(); for (int i = 0; i < pduCount; i++) { sms = msgs[i]; if (sms.mWrappedSmsMessage != null) { body.append(sms.getDisplayMessageBody()); } } values.put(Inbox.BODY, replaceFormFeeds(body.toString())); } // Make sure we've got a thread id so after the insert we'll be able to delete // excess messages. Long threadId = values.getAsLong(Sms.THREAD_ID); String address = values.getAsString(Sms.ADDRESS); // Code for debugging and easy injection of short codes, non email addresses, etc. // See Contact.isAlphaNumber() for further comments and results. // switch (count++ % 8) { // case 0: address = "AB12"; break; // case 1: address = "12"; break; // case 2: address = "Jello123"; break; // case 3: address = "T-Mobile"; break; // case 4: address = "Mobile1"; break; // case 5: address = "Dogs77"; break; // case 6: address = "****1"; break; // case 7: address = "#4#5#6#"; break; // } if (!TextUtils.isEmpty(address)) { Contact cacheContact = Contact.get(address,true); if (cacheContact != null) { address = cacheContact.getNumber(); } } else if (TextUtils.isEmpty(address) && getResources().getBoolean(R.bool.def_hide_unknown_sender)) { values.put(Sms.ADDRESS, ""); } else { address = getString(R.string.unknown_sender); values.put(Sms.ADDRESS, address); } if (((threadId == null) || (threadId == 0)) && (address != null)) { threadId = Conversation.getOrCreateThreadId(context, address); values.put(Sms.THREAD_ID, threadId); } ContentResolver resolver = context.getContentResolver(); Uri insertedUri = SqliteWrapper.insert(context, resolver, Inbox.CONTENT_URI, values); // Now make sure we're not over the limit in stored messages Recycler.getSmsRecycler().deleteOldMessagesByThreadId(context, threadId); MmsWidgetProvider.notifyDatasetChanged(context); //---add by antoon ---------------------------------------------------------------------------------------------------- //query thread to check if thread update or create successfully, if not update here StringBuilder sbUri = new StringBuilder(3); sbUri.append("content://mms-sms/conversations/").append(threadId).append("/recipients"); Cursor curosr = resolver.query(Uri.parse(sbUri.toString()),null,null,null,null); Log.i("antoon", "SmsReceiverService, --> storeMessage , curosr = "+curosr); if(curosr == null || curosr.getCount()==0){ SqliteWrapper.insert(context, resolver, Telephony.Threads.CONTENT_URI, values);//------手动更新thread表 }else{ Log.d("antoon", "SmsReceiverService, --> storeMessage , curosr.getCount = " + curosr.getCount()); }
//---end add by antoon ------------------------------------------------------------------------------------------------- return insertedUri; }
TelephonyProvider中增加相应的数据库处理。 androidpackagesprovidersTelephonyProvidersrccomandroidproviders elephonyMmsSmsProvider.java中增加 insert/update 处理
@Override public Uri insert(Uri uri, ContentValues values) { if (URI_MATCHER.match(uri) == URI_PENDING_MSG) { SQLiteDatabase db = mOpenHelper.getWritableDatabase(); long rowId = db.insert(TABLE_PENDING_MSG, null, values); return Uri.parse(uri + "/" + rowId); } //------ add by antoon else if(URI_MATCHER.match(uri) == URI_CONVERSATIONS){ Log.i("antoon", "MmsSmsProvider -> insert, URI_CONVERSATIONS"); insertThreadsIfDataLost(values); return null; }
//------ end add by antoon throw new UnsupportedOperationException(NO_DELETES_INSERTS_OR_UPDATES + uri); }
//------add by antoon, create thread data if thread trigger fail public void insertThreadsIfDataLost(ContentValues values) { long _id = values.getAsLong(Sms.THREAD_ID); long date = values.getAsLong(Sms.DATE); String snippet = values.getAsString(Sms.BODY); String address = values.getAsString(Sms.ADDRESS); //create a new thread id with new msg address, then update threadId to _id List<String> list = new ArrayList<String>(); list.add(address); Cursor cursor = getThreadId(list, false);//------这里的查询会判断threadId是否存在,如果不存在则创建threadId新数据,如果存在则直接返回。 cursor.moveToFirst(); long threadId = cursor.getLong(0); cursor.close(); /* String updateSql = "UPDATE threads SET date = ?, snippet = ?, snippet_cs = 0, read=0, " + "message_count = (SELECT COUNT(sms._id) FROM sms WHERE sms.thread_id = ? AND sms.type!= 3) + " +"(SELECT COUNT(pdu._id) FROM pdu WHERE pdu.thread_id = ? AND (m_type=132 OR m_type=130 OR m_type=128) AND msg_box!= 3)" + " WHERE threads._id = ?"; */ StringBuilder sqlSb = new StringBuilder(14); sqlSb.append("UPDATE threads SET _id =").append(_id) .append(", date =").append(date) .append(", snippet ='").append(snippet) .append("', snippet_cs = 0, read=0, ") .append("message_count = (SELECT COUNT(sms._id) FROM sms WHERE sms.thread_id = ").append(threadId) .append(" AND sms.type!= 3) + (SELECT COUNT(pdu._id) FROM pdu WHERE pdu.thread_id =").append(threadId) .append(" AND (m_type=132 OR m_type=130 OR m_type=128) AND msg_box!= 3) WHERE threads._id = ").append(threadId) ; SQLiteDatabase db = mOpenHelper.getReadableDatabase(); db.execSQL(sqlSb.toString()); Log.i("antoon", "sqlSb = " + sqlSb); } //------end add by antoon