Let’s say you are developing an Android app com.example.android and want to access its database file named “content” from the test device/emulator. To access this file, located in app’s database directory, on both rooted and unrooted device would be

Bash
1
2
3
4
5
$ APP_NAME=com.example.android
$ adb shell run-as $APP_NAME cp databases/content.db /sdcard/content.db &&
$ adb pull /sdcard/content.db content.db &&
$ adb shell rm /sdcard/content.db
...

This seems to work but is incorrect. An SQLite database can have write-ahead logging (-wal) file, a journal (-journal), and shared memory (-shm) file. Anytime, you copy just the .db file; you might get an old copy of the database, the right way to copy is to copy all the four files, so that, the SQLite on the laptop displays the combined result.

You can use adb-enhanced to do this correctly

Bash
1
2
3
4
$ sudo pip3 install adb-enhanced # One-time install
# -a copies all the ancially files
$ adbe pull -a /data/data/com.example.android/databases/content.db
...

Here is a generalized bash script if you don’t want to install a new tool

Bash
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# Sample invocation: get_db com.example.android content.db
get_db() {
    if [ -z "$1" ]
    then
        echo "Please provide the qualified package name as the first argument"
        return 1
    fi

    if [ -z "$2" ]
    then
        echo "Please provide the file name (not path) as the second argument"
        return 1
    fi

    FILES=(${2} ${2}-wal ${2}-shm ${2}-journal) # Get the list of all the files
    for file in ${FILES[@]}
    do
        # Suppress useless errors, all the files are not expected to exist.
        adb shell run-as ${1} cp databases/${file} /sdcard/${file} > /dev/null &&
            adb pull /sdcard/${file} > /dev/null &&
            adb shell rm /sdcard/${file} > /dev/null &&
            echo "Copied ${file}";
    done
}