Android Contacts: contacts2.db
The Android contacts provider database: raw contacts per account, the data and mimetypes tables, messaging app accounts and the deleted_contacts log.
- Location
- /data/data/com.android.providers.contacts/databases/contacts2.db
- Proves
- Which contacts exist on the device, from which account (Google, SIM, WhatsApp, Telegram, Signal...), their numbers and emails, and when contacts were changed or deleted
- Timestamps
- contacts.contact_last_updated_timestamp and deleted_contacts.contact_deleted_timestamp in Unix milliseconds (UTC); usage columns frozen since Android 10
- Access
- Full file system (root, exploit or agent); credential-encrypted storage, so AFU only. Logical: provider view through an agent app. Not in ADB backup or bugreport (dumpsys account lists the accounts only).
- Retention
- Until deleted or unsynced; deleted_contacts keeps IDs and deletion times for about 30 days; synced accounts also persist server-side
- Collection
- Full file system extraction, Agent-based logical extraction, Google account export (cloud)
Tools
Compare all toolsWhat it is
contacts2.db is the database of Android's contacts provider (com.android.providers.contacts). It stores every contact the device knows about, whatever its origin: the Google account, the SIM card, Exchange, a phone-only local account, and the accounts that messaging apps register to publish their users in the address book. Apps read it through content://com.android.contacts.
For an investigator it answers two questions at once: who the user knows, and which apps and accounts were set up on the device, because each sync adapter leaves its own account type behind.
Where it lives
| Item | Path | Notes |
|---|---|---|
| Database | /data/data/com.android.providers.contacts/databases/contacts2.db | Same as /data/user/0/...; credential-encrypted storage |
| Owner profile | /data/data/com.android.providers.contacts/databases/profile.db | The "Me" card: often the device owner's own name, number and email |
| Contact photos | /data/data/com.android.providers.contacts/files/photos/ | Full-size photos; thumbnails are stored in the photo rows of data |
| Call log (Android 7+) | calllog.db in device-encrypted storage | See call log |
| Other users | /data/user/<user>/com.android.providers.contacts/ | Work profiles have a separate store |
The layout is unchanged from Android 8 to 16. Samsung builds use the same provider and add account types such as vnd.sec.contact.phone (device contacts) and vnd.sec.contact.sim.
What it proves
- The contacts present at acquisition time, their numbers, emails, addresses, organisations, notes and groups.
- Which account each contact came from (
accounts.account_typeandaccount_name), which reveals the Google account email and the presence of messaging apps (com.whatsapp,org.telegram.messenger,org.thoughtcrime.securesmsfor Signal,com.viber.voip). - That a contact was deleted, and when, through
deleted_contactsor rows flaggeddeleted = 1awaiting sync. - When an aggregated contact last changed (
contact_last_updated_timestamp).
It does not prove the user created a contact by hand: sync adapters and apps create most rows automatically.
Key fields
| Table | Column | Meaning |
|---|---|---|
accounts | account_name, account_type | Account the rows sync with, e.g. alice@example.com / com.google |
raw_contacts | account_id, contact_id, display_name, deleted, starred, dirty | One row per contact per account; deleted = 1 means pending removal |
contacts | name_raw_contact_id, contact_last_updated_timestamp, starred, lookup | Aggregated person across accounts |
data | raw_contact_id, mimetype_id, data1 to data15 | Each piece of information; meaning depends on the mimetype |
mimetypes | mimetype | vnd.android.cursor.item/phone_v2, email_v2, name, organization, photo, note, plus app types like vnd.android.cursor.item/vnd.com.whatsapp.profile |
phone_lookup | normalized_number, raw_contact_id | Index for matching numbers from calls and SMS |
deleted_contacts | contact_id, contact_deleted_timestamp | Deletion log |
raw_contacts / contacts | times_contacted, last_time_contacted | Usage counters, no longer maintained from Android 10 |
Timestamps
contact_last_updated_timestamp and contact_deleted_timestamp are Unix milliseconds (UTC). Android 10 stopped recording times_contacted and last_time_contacted: on newer builds they are zero or frozen legacy values, not evidence of recent contact.
SELECT rc._id AS raw_id, a.account_type, a.account_name,
rc.display_name, rc.deleted, m.mimetype, d.data1
FROM raw_contacts rc
JOIN accounts a ON a._id = rc.account_id
JOIN data d ON d.raw_contact_id = rc._id
JOIN mimetypes m ON m._id = d.mimetype_id
WHERE m.mimetype IN ('vnd.android.cursor.item/phone_v2',
'vnd.android.cursor.item/email_v2')
ORDER BY rc.display_name;
SELECT contact_id, datetime(contact_deleted_timestamp/1000, 'unixepoch') AS deleted_utc
FROM deleted_contacts ORDER BY contact_deleted_timestamp;
Retention
Contacts remain until deleted locally, removed by their sync adapter (for example when an account is removed from the phone or a messaging app is uninstalled), or wiped by a factory reset. deleted_contacts keeps an entry for about 30 days so sync clients can catch up; only IDs and times survive there, not names. Deleted data rows can linger in free pages and the WAL. Google account contacts also exist server-side, retrievable through the account holder's export or legal process.
Collection
- Full file system extraction is needed for the database itself, the owner profile and photos. It is in credential-encrypted storage, so the phone must be AFU (see file-based encryption).
- Logical: every agent-based extraction reads contacts through the provider; the result lacks deleted rows and raw account structure on some tools.
- Bugreport:
dumpsys accountlists the accounts configured on the device, which is useful context even without the contacts themselves.
Parsing
ALEAPP, Andriller and Autopsy report contacts and accounts; commercial suites resolve every mimetype. For your own queries, always join through mimetypes: the numeric mimetype_id values differ from device to device.
Investigator tips
- List
accountsfirst: it is a quick inventory of Google accounts and messaging apps, including apps since uninstalled if their raw contacts were not cleaned up. - WhatsApp, Telegram and Signal raw contacts show which address book entries are users of that app, which helps attribute chat partners found in WhatsApp to a real name.
- Match numbers from SMS and the call log through
phone_lookup.normalized_number, not raw strings: formats differ (+33,0033, spaces). - A burst of
deleted_contactsrows shortly before seizure is worth putting on the timeline next to app installs and removals. - Check
profile.db: the device owner's own card often gives a name and number the user never typed elsewhere.