Merge "[People Service] Prevent system_server crashes due to Content Provider issues in People Service" into main
diff --git a/services/people/java/com/android/server/people/data/CallLogQueryHelper.java b/services/people/java/com/android/server/people/data/CallLogQueryHelper.java
index ff901af..30df4c8 100644
--- a/services/people/java/com/android/server/people/data/CallLogQueryHelper.java
+++ b/services/people/java/com/android/server/people/data/CallLogQueryHelper.java
@@ -96,6 +96,8 @@
         } catch (SecurityException ex) {
             Slog.e(TAG, "Query call log failed: " + ex);
             return false;
+        } catch (Exception e) {
+            Slog.e(TAG, "Exception when querying call log.", e);
         }
         return hasResults;
     }
diff --git a/services/people/java/com/android/server/people/data/ContactsQueryHelper.java b/services/people/java/com/android/server/people/data/ContactsQueryHelper.java
index 2505abf2..2bd9d87 100644
--- a/services/people/java/com/android/server/people/data/ContactsQueryHelper.java
+++ b/services/people/java/com/android/server/people/data/ContactsQueryHelper.java
@@ -151,9 +151,11 @@
                 found = true;
             }
         } catch (SQLiteException exception) {
-            Slog.w("SQLite exception when querying contacts.", exception);
+            Slog.w(TAG, "SQLite exception when querying contacts.", exception);
         } catch (IllegalArgumentException exception) {
-            Slog.w("Illegal Argument exception when querying contacts.", exception);
+            Slog.w(TAG, "Illegal Argument exception when querying contacts.", exception);
+        } catch (Exception exception) {
+            Slog.e(TAG, "Exception when querying contacts.", exception);
         }
         if (found && lookupKey != null && hasPhoneNumber) {
             return queryPhoneNumber(lookupKey);
@@ -181,6 +183,8 @@
                     mPhoneNumber = cursor.getString(phoneNumIdx);
                 }
             }
+        } catch (Exception exception) {
+            Slog.e(TAG, "Exception when querying contact phone number.", exception);
         }
         return true;
     }
diff --git a/services/people/java/com/android/server/people/data/MmsQueryHelper.java b/services/people/java/com/android/server/people/data/MmsQueryHelper.java
index 39dba9c..414a523 100644
--- a/services/people/java/com/android/server/people/data/MmsQueryHelper.java
+++ b/services/people/java/com/android/server/people/data/MmsQueryHelper.java
@@ -100,6 +100,8 @@
                     }
                 }
             }
+        } catch (Exception e) {
+            Slog.e(TAG, "Exception when querying MMS table.", e);
         } finally {
             Binder.defaultBlockingForCurrentThread();
         }
@@ -133,6 +135,8 @@
                     address = cursor.getString(addrIndex);
                 }
             }
+        } catch (Exception e) {
+            Slog.e(TAG, "Exception when querying MMS address table.", e);
         }
         if (!Mms.isPhoneNumber(address)) {
             return null;
diff --git a/services/people/java/com/android/server/people/data/SmsQueryHelper.java b/services/people/java/com/android/server/people/data/SmsQueryHelper.java
index a5eb3a5..f8ff3ab 100644
--- a/services/people/java/com/android/server/people/data/SmsQueryHelper.java
+++ b/services/people/java/com/android/server/people/data/SmsQueryHelper.java
@@ -98,6 +98,8 @@
                     }
                 }
             }
+        } catch (Exception e) {
+            Slog.e(TAG, "Exception when querying SMS table.", e);
         } finally {
             Binder.defaultBlockingForCurrentThread();
         }
diff --git a/services/tests/servicestests/src/com/android/server/people/data/CallLogQueryHelperTest.java b/services/tests/servicestests/src/com/android/server/people/data/CallLogQueryHelperTest.java
index a545010..f45eddc 100644
--- a/services/tests/servicestests/src/com/android/server/people/data/CallLogQueryHelperTest.java
+++ b/services/tests/servicestests/src/com/android/server/people/data/CallLogQueryHelperTest.java
@@ -24,6 +24,7 @@
 
 import android.database.Cursor;
 import android.database.MatrixCursor;
+import android.database.sqlite.SQLiteException;
 import android.net.Uri;
 import android.provider.CallLog.Calls;
 import android.test.mock.MockContentProvider;
@@ -58,6 +59,7 @@
     private MatrixCursor mCursor;
     private EventConsumer mEventConsumer;
     private CallLogQueryHelper mHelper;
+    private CallLogContentProvider mCallLogContentProvider;
 
     @Before
     public void setUp() {
@@ -66,7 +68,8 @@
         mCursor = new MatrixCursor(CALL_LOG_COLUMNS);
 
         MockContentResolver contentResolver = new MockContentResolver();
-        contentResolver.addProvider(CALL_LOG_AUTHORITY, new CallLogContentProvider());
+        mCallLogContentProvider = new CallLogContentProvider();
+        contentResolver.addProvider(CALL_LOG_AUTHORITY, mCallLogContentProvider);
         when(mContext.getContentResolver()).thenReturn(contentResolver);
 
         mEventConsumer = new EventConsumer();
@@ -80,6 +83,12 @@
     }
 
     @Test
+    public void testQueryWithSQLiteException() {
+        mCallLogContentProvider.setThrowSQLiteException(true);
+        assertFalse(mHelper.querySince(50L));
+    }
+
+    @Test
     public void testQueryIncomingCall() {
         mCursor.addRow(new Object[] {
                 NORMALIZED_PHONE_NUMBER, /* date= */ 100L, /* duration= */ 30L,
@@ -159,11 +168,20 @@
     }
 
     private class CallLogContentProvider extends MockContentProvider {
+        private boolean mThrowSQLiteException = false;
 
         @Override
         public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
                 String sortOrder) {
+            if (mThrowSQLiteException) {
+                throw new SQLiteException();
+            }
+
             return mCursor;
         }
+
+        public void setThrowSQLiteException(boolean throwException) {
+            this.mThrowSQLiteException = throwException;
+        }
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/people/data/ContactsQueryHelperTest.java b/services/tests/servicestests/src/com/android/server/people/data/ContactsQueryHelperTest.java
index 16a02b6..1daee39 100644
--- a/services/tests/servicestests/src/com/android/server/people/data/ContactsQueryHelperTest.java
+++ b/services/tests/servicestests/src/com/android/server/people/data/ContactsQueryHelperTest.java
@@ -99,6 +99,14 @@
     }
 
     @Test
+    public void testQueryOtherException_returnsFalse() {
+        contentProvider.setThrowOtherException(true);
+
+        Uri contactUri = Uri.withAppendedPath(Contacts.CONTENT_LOOKUP_URI, CONTACT_LOOKUP_KEY);
+        assertFalse(mHelper.query(contactUri.toString()));
+    }
+
+    @Test
     public void testQueryIllegalArgumentException_returnsFalse() {
         contentProvider.setThrowIllegalArgumentException(true);
 
@@ -152,6 +160,13 @@
     }
 
     @Test
+    public void testQueryWithPhoneNumber_otherExceptionReturnsFalse() {
+        contentProvider.setThrowOtherException(true);
+        String contactUri = "tel:" + PHONE_NUMBER;
+        assertFalse(mHelper.query(contactUri));
+    }
+
+    @Test
     public void testQueryWithEmail() {
         mContactsLookupCursor.addRow(new Object[] {
                 /* id= */ 11, CONTACT_LOOKUP_KEY, /* starred= */ 1, /* hasPhoneNumber= */ 0 });
@@ -188,6 +203,7 @@
         private Map<Uri, Cursor> mUriPrefixToCursorMap = new ArrayMap<>();
         private boolean mThrowSQLiteException = false;
         private boolean mThrowIllegalArgumentException = false;
+        private boolean mThrowOtherException = false;
 
         @Override
         public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
@@ -198,6 +214,9 @@
             if (mThrowIllegalArgumentException) {
                 throw new IllegalArgumentException();
             }
+            if (mThrowOtherException) {
+                throw new ArrayIndexOutOfBoundsException();
+            }
 
             for (Uri prefixUri : mUriPrefixToCursorMap.keySet()) {
                 if (uri.isPathPrefixMatch(prefixUri)) {
@@ -215,6 +234,10 @@
             this.mThrowIllegalArgumentException = throwException;
         }
 
+        public void setThrowOtherException(boolean throwException) {
+            this.mThrowOtherException = throwException;
+        }
+
         private void registerCursor(Uri uriPrefix, Cursor cursor) {
             mUriPrefixToCursorMap.put(uriPrefix, cursor);
         }
diff --git a/services/tests/servicestests/src/com/android/server/people/data/MmsQueryHelperTest.java b/services/tests/servicestests/src/com/android/server/people/data/MmsQueryHelperTest.java
index 7730890..9f4a43df 100644
--- a/services/tests/servicestests/src/com/android/server/people/data/MmsQueryHelperTest.java
+++ b/services/tests/servicestests/src/com/android/server/people/data/MmsQueryHelperTest.java
@@ -23,6 +23,7 @@
 
 import android.database.Cursor;
 import android.database.MatrixCursor;
+import android.database.sqlite.SQLiteException;
 import android.net.Uri;
 import android.provider.Telephony.BaseMmsColumns;
 import android.provider.Telephony.Mms;
@@ -63,6 +64,7 @@
     private final List<MatrixCursor> mAddrCursors = new ArrayList<>();
     private EventConsumer mEventConsumer;
     private MmsQueryHelper mHelper;
+    private MmsContentProvider mMmsContentProvider;
 
     @Before
     public void setUp() {
@@ -73,7 +75,8 @@
         mAddrCursors.add(new MatrixCursor(ADDR_COLUMNS));
 
         MockContentResolver contentResolver = new MockContentResolver();
-        contentResolver.addProvider(MMS_AUTHORITY, new MmsContentProvider());
+        mMmsContentProvider = new MmsContentProvider();
+        contentResolver.addProvider(MMS_AUTHORITY, mMmsContentProvider);
         when(mContext.getContentResolver()).thenReturn(contentResolver);
 
         mEventConsumer = new EventConsumer();
@@ -87,6 +90,12 @@
     }
 
     @Test
+    public void testQueryWithSQLiteException() {
+        mMmsContentProvider.setThrowSQLiteException(true);
+        assertFalse(mHelper.querySince(50_000L));
+    }
+
+    @Test
     public void testQueryIncomingMessage() {
         mMmsCursor.addRow(new Object[] {
                 /* id= */ 0, /* date= */ 100L, /* msgBox= */ BaseMmsColumns.MESSAGE_BOX_INBOX });
@@ -159,10 +168,15 @@
     }
 
     private class MmsContentProvider extends MockContentProvider {
+        private boolean mThrowSQLiteException = false;
 
         @Override
         public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
                 String sortOrder) {
+            if (mThrowSQLiteException) {
+                throw new SQLiteException();
+            }
+
             List<String> segments = uri.getPathSegments();
             if (segments.size() == 2 && "addr".equals(segments.get(1))) {
                 int messageId = Integer.valueOf(segments.get(0));
@@ -170,5 +184,9 @@
             }
             return mMmsCursor;
         }
+
+        public void setThrowSQLiteException(boolean throwException) {
+            this.mThrowSQLiteException = throwException;
+        }
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/people/data/SmsQueryHelperTest.java b/services/tests/servicestests/src/com/android/server/people/data/SmsQueryHelperTest.java
index 5cb8cb4..09a0dff 100644
--- a/services/tests/servicestests/src/com/android/server/people/data/SmsQueryHelperTest.java
+++ b/services/tests/servicestests/src/com/android/server/people/data/SmsQueryHelperTest.java
@@ -23,6 +23,7 @@
 
 import android.database.Cursor;
 import android.database.MatrixCursor;
+import android.database.sqlite.SQLiteException;
 import android.net.Uri;
 import android.provider.Telephony.Sms;
 import android.provider.Telephony.TextBasedSmsColumns;
@@ -59,6 +60,7 @@
     private MatrixCursor mSmsCursor;
     private EventConsumer mEventConsumer;
     private SmsQueryHelper mHelper;
+    private SmsContentProvider mSmsContentProvider;
 
     @Before
     public void setUp() {
@@ -67,7 +69,8 @@
         mSmsCursor = new MatrixCursor(SMS_COLUMNS);
 
         MockContentResolver contentResolver = new MockContentResolver();
-        contentResolver.addProvider(SMS_AUTHORITY, new SmsContentProvider());
+        mSmsContentProvider = new SmsContentProvider();
+        contentResolver.addProvider(SMS_AUTHORITY, mSmsContentProvider);
         when(mContext.getContentResolver()).thenReturn(contentResolver);
 
         mEventConsumer = new EventConsumer();
@@ -130,6 +133,12 @@
         assertEquals(110L, events.get(1).getTimestamp());
     }
 
+    @Test
+    public void testQueryWithSQLiteException() {
+        mSmsContentProvider.setThrowSQLiteException(true);
+        assertFalse(mHelper.querySince(50L));
+    }
+
     private class EventConsumer implements BiConsumer<String, Event> {
 
         private final Map<String, List<Event>> mEventMap = new ArrayMap<>();
@@ -141,11 +150,19 @@
     }
 
     private class SmsContentProvider extends MockContentProvider {
+        private boolean mThrowSQLiteException = false;
 
         @Override
         public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
                 String sortOrder) {
+            if (mThrowSQLiteException) {
+                throw new SQLiteException();
+            }
             return mSmsCursor;
         }
+
+        public void setThrowSQLiteException(boolean throwException) {
+            this.mThrowSQLiteException = throwException;
+        }
     }
 }