Skip to content

CommunicationsDevice & system

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)

What 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

ItemPathNotes
Database/data/data/com.android.providers.contacts/databases/contacts2.dbSame as /data/user/0/...; credential-encrypted storage
Owner profile/data/data/com.android.providers.contacts/databases/profile.dbThe "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 storageSee 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_type and account_name), which reveals the Google account email and the presence of messaging apps (com.whatsapp, org.telegram.messenger, org.thoughtcrime.securesms for Signal, com.viber.voip).
  • That a contact was deleted, and when, through deleted_contacts or rows flagged deleted = 1 awaiting 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

TableColumnMeaning
accountsaccount_name, account_typeAccount the rows sync with, e.g. alice@example.com / com.google
raw_contactsaccount_id, contact_id, display_name, deleted, starred, dirtyOne row per contact per account; deleted = 1 means pending removal
contactsname_raw_contact_id, contact_last_updated_timestamp, starred, lookupAggregated person across accounts
dataraw_contact_id, mimetype_id, data1 to data15Each piece of information; meaning depends on the mimetype
mimetypesmimetypevnd.android.cursor.item/phone_v2, email_v2, name, organization, photo, note, plus app types like vnd.android.cursor.item/vnd.com.whatsapp.profile
phone_lookupnormalized_number, raw_contact_idIndex for matching numbers from calls and SMS
deleted_contactscontact_id, contact_deleted_timestampDeletion log
raw_contacts / contactstimes_contacted, last_time_contactedUsage 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 account lists 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 accounts first: 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_contacts rows 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.

See also