android C++ database

AndroidからSQLiteのDBファイルを取り出す方法をAndroidソースから調べる

投稿日:2019年5月29日

AndroidからDBファイルを取り出し、PCに持ってきて、「PupSQLite」や「DB Browser for SQLite」などのツールで内容を確認出来るようにします。

コマンドラインで自動取得できるようにしておくことで、CIサイクル中にDBファイルを取ってきてスキーマ自動作成などが出来る環境を整えておきます。

DBファイルの場所を確認

PCにAndroidをUSB接続し、認識しているか確認します。

C:\>adb devices
List of devices attached
FA7761800334    device

Androidのシェルに入ります。

C:\>adb shell
htc_ocnuhljapan:/ $

run-asで開発アプリのパッケージディレクトリに入ります。root化しない限りこのディレクトリから外へはアクセス出来ません。また、インストールしたユーザに入られてクラックされても困りますから、アプリがリリースビルドされている場合はこの操作は出来ません。

htc_ocnuhljapan:/ $ run-as jp.co.xyz
htc_ocnuhljapan:/data/data/jp.co.xyz $ pwd
/data/data/jp.co.xyz

パッケージディレクトリ内にdatabasesというディレクトリがあります。

htc_ocnuhljapan:/data/data/jp.co.xyz $ ls
app_database app_webview code_cache shared_prefs
app_textures cache       databases

この中にアプリで作成したSQLiteのDBファイルが保存されています。

htc_ocnuhljapan:/data/data/jp.co.xyz $ cd databases
htc_ocnuhljapan:/data/data/jp.co.xyz/databases $ ls
awesomeapp.db  ← SQLIteのDBファイル

このawesomeapp.dbをPCに持ってくる方法を考えます。

Android5からアクセス権限が厳しくなった

Android5(Lolipop)からAndroidOS内のパーミッションが厳しくなりました。それ以前は一旦外から直接アクセスできるディレクトリにDBファイルをコピーしておき、adb pullを使って取ってきていました。

set PACKAGE=jp.co.xyz.awsameapp
set TEMPFILE=/mnt/shell/emulated/0/Android/data/%PACKAGE%/files
set DBFILEE=awsameapp.db

adb -d shell "run-as %PACKAGE% cat databases/%DBFILE% > %TEMPFILE%/%DBFILE%"

adb pull %TEMPFILE%/%DBFILE% 

自パッケージディレクトリ以外に完全にアクセス出来なくなった為、昨今のAndroidではこの手法が取れなくなってしまいました。

回避策

Androidのadbコマンド関連ソースを見ると、/system/core/adb/commandline.cppの中で、adbにはexec-outという公開されていないオプションが有り、out_to_file(int inFd, int outFd)という関数を呼んでいて、指定したファイルデスクプリタの内容をPCの標準出力に流してくれることが分かります。

// adbオプションでexec-outが指定されたか判定をしてる

    else if (!strcmp(argv[0], "exec-in") || !strcmp(argv[0], "exec-out")) {

        (snip)

        if (exec_in) {
            copy_to_file(STDIN_FILENO, fd);
        } else {
            copy_to_file(fd, STDOUT_FILENO);
        }

// 入力ファイルデスクリプタ内容をPCの標準出力にコピーしてる

static void copy_to_file(int inFd, int outFd) {
    const size_t BUFSIZE = 32 * 1024;
    char* buf = (char*) malloc(BUFSIZE);
    if (buf == nullptr) fatal("couldn't allocate buffer for copy_to_file");
    int len;
    long total = 0;
    int old_stdin_mode = -1;
    int old_stdout_mode = -1;

    D("copy_to_file(%d -> %d)", inFd, outFd);

    stdinout_raw_prologue(inFd, outFd, old_stdin_mode, old_stdout_mode);

    while (true) {
        if (inFd == STDIN_FILENO) {
            len = unix_read(inFd, buf, BUFSIZE);
        } else {
            len = adb_read(inFd, buf, BUFSIZE);
        }
        if (len == 0) {
            D("copy_to_file() : read 0 bytes; exiting");
            break;
        }
        if (len < 0) {
            D("copy_to_file(): read failed: %s", strerror(errno));
            break;
        }
        if (outFd == STDOUT_FILENO) {
            fwrite(buf, 1, len, stdout);
            fflush(stdout);
        } else {
            adb_write(outFd, buf, len);
        }
        total += len;
    }

    stdinout_raw_epilogue(inFd, outFd, old_stdin_mode, old_stdout_mode);

    D("copy_to_file() finished after %lu bytes", total);
    free(buf);
}

この機能を利用すると端末内のdatabases/awsomeapp.dbファイルをcatし、ローカルPCのカレントディレクトリにリダイレクトできるようになります。

adb exec-out run-as jp.co.xyz cat databases/awesomeapp.db > ./awesomeapp.db

後はこれを直接使用するなり、Cordova系のハイブリッドアプリであればpackage.jsonでnpmスクリプト定義しておくなりしておきます。

以下「npm run getdb」を実行するとカレントディレクトリにDBファイルが吐き出されるpackage.json。

{
    (snip)

    "scripts": {

        (snip)

        "getdb": "adb exec-out run-as jp.co.xyz cat databases/awesomeapp.db > ./awesomeapp.db"
    },

exec-outはadbコマンドのヘルプにも出ておらず、GoogleのAndroid Deveropersサイトのドキュメントにも載っていないイースターエッグ的なオプションです。今後無くなる可能性は無きにしも非ずです。

今の所exec-outオプションの存在はネット検索で情報が見つかりますが、もしexec-outが無くなったらネットに新しい方法が流れるまで時間が掛かるかも知れません。自分でソースを調べればネットに情報が出てくるまで待たなくて済みます。

補足

/development/tools/winscope/capture_sf_trace.shというシェルの中でこんなadbコマンド使用例があります。

adb exec-out su root cat /data/misc/trace/layerstrace.pb >"$outfile"

exec-outはGoogle内のプログラマが使う為のオプションなんですね。ついでに利用させて貰いましょう。

-android, C++, database

執筆者:

関連記事

Stripe + Javaでオーソリ(与信の確保)を実装する

Stripeでチャリンチャリン、サービスを開発するエンジニアにとっては夢がありますよね。 例え自分で個人的に売るものが無かったとしても、Web決済システムを構築できるノウハウを持っておけば、公的な仕事 …

Stripe+Java+Payment Request APIでApple Pay、Google Payを使ったテストWeb決済をしてみる

自分で作ったサービスを運用してチャリンチャリンしたい・・・エンジニアならこんな夢、一度は見たことがあるんじゃないでしょうか。 夢を実現する為、以前Stripeのcheckout.jsを使ったテストWe …

Android版ChromiumをVirtualBoxにインストールしたUbuntuでビルドしてみる

「Chromium」はChromeの開発ソースが公開されたプロジェクトです。 www.chromium.org  1 UserGet the Code: Checkout, Build, & …

Javascriptでコンパスを作ってAndroid、iPhoneが向いている方角を特定

普段は意識しなくても、AndroidもiPhoneも自然データをデジタルに変換するセンサーの塊です。 加速度センサー重力センサージャイロセンサー地磁気センサー気圧センサー照度センサー温度センサー位置セ …

【タップするだけ】インスタグラム、twitterのプロフィール画像を簡単に拡大表示する方法(iPhone、Android)

インスタのプロフィール画像って小さくてよく見えないですよね・・・。 インスタに限らず「何が写ってるのかスマホ画面を拡大して見たいな」という時は「設定」から「アクセシビリティ」を設定することで拡大表示機 …

 

shingo.nakanishi
 

東京在勤、1977年生まれ、IT職歴2n年、生涯技術者として楽しく生きることを目指しています。デスマに負けず健康第一。