Javaからnativeの関数に byte[]配列を渡してそれをファイルに書き込む関数を作ってみた。以下のJavaソースをjavahで変換して対応するヘッダファイルを作成。
FileManager.java
- package test.filetest;
- public class FileManager {
- public native int write(byte[] data);
- static { System.loadLibrary("filetest"); }
- }
test_filetest_FileManager.h
- #include <jni.h>
- #ifndef _Included_test_filetest_FileManager
- #define _Included_test_filetest_FileManager
- #ifdef __cplusplus
- extern "C" {
- #endif
- JNIEXPORT jint JNICALL Java_test_filetest_FileManager_write
- (JNIEnv *, jobject, jbyteArray);
- #ifdef __cplusplus
- }
- #endif
- #endif
Java_test_filetest_FileManager_write関数の実装は以下のようにしてみた。エラーから抜けるのにgotoを多用しているので人により好き嫌いあるかもしれないが、NDKだとtry-catchが使えないようなのでこの方法が楽といえば楽。
test_filetest_FileManager.cpp
- #include "test_filetest_FileManager.h"
- #include <string.h>
- #include <fcntl.h>
- #include <android/log.h>
- #define _DBGPRINTF(...) __android_log_print(3, "filetest", __VA_ARGS__)
- JNIEXPORT jint JNICALL Java_test_filetest_FileManager_write
- (JNIEnv* env, jobject caller, jbyteArray jBin)
- {
- jbyte* bin = NULL;
- int binSize;
- int err = 0;
- int s;
- _DBGPRINTF("Java_test_filetest_FileManager_write");
- // ファイルを /data/data/{pkgname} 以下のフォルダに読み書きする
- // ここでは hello.dat を書き込み用にオープン(O_WRONLY)。無ければ作成(O_CREAT)
- // ファイルのmodeを 0666 に設定
- int fd = open("/data/data/test.filetest/hello.dat",
- O_WRONLY|O_CREAT,
- S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
- _DBGPRINTF("fd=%d\n", fd);
- if (fd < 0) {
- _DBGPRINTF("Error: open");
- err = -1;
- goto error_exit0;
- }
- // 渡されたJava byte配列を C byte 配列に変換
- bin = env->GetByteArrayElements(jBin, NULL);
- if (bin == NULL) {
- _DBGPRINTF("Error: GetByteArrayElements");
- err = -1;
- goto error_exit1;
- }
- // 渡されたJava byte配列の長さを取得
- binSize = env->GetArrayLength(jBin);
- _DBGPRINTF("Write: %d bytes");
- // writeで書き込み
- s = write(fd, (void*)bin, binSize);
- _DBGPRINTF("Write: ret=%d", s);
- if (s < 0) {
- _DBGPRINTF("Error: write");
- err = -1;
- }
- // C byte配列を使い終わったのでメモリから解放
- env->ReleaseByteArrayElements(jBin, bin, 0);
- error_exit1:
- // ファイルクローズ
- close(fd);
- error_exit0:
- return err;
- }
Androidのファイルシステムの中身は adb shell コマンドでシェルに入ることで確認できる。プログラムを実行すると、/data/data/test.filetestフォルダには確かにファイルができていた。
# cd /data/data/test.filetest
cd /data/data/test.filetest
# ls -l
ls -l
-rwxr-xrwT app_28 app_28 256 2010-09-09 13:31 hello.dat
drwxr-xr-x system system 2010-09-09 13:23 lib
その上位のフォルダ一覧を見てみると、フォルダ(パッケージ名)ごとに所有者やパーミションがついているのがわかる。アプリごとに所有者が違うということはAndroidはこの仕組みを使ってアプリごとのアクセス管理をしているのだろうか?
# cd /data/data
cd /data/data
# ls -l
ls -l
drwxr-xr-x app_28 app_28 2010-09-09 13:23 test.filetest
drwxr-xr-x app_24 app_24 2010-07-14 12:15 jp.hews.intent
drwxr-xr-x app_21 app_21 2010-01-27 13:32 com.android.mms
drwxr-xr-x app_5 app_5 2010-01-27 13:32 com.android.camera
drwxr-xr-x app_4 app_4 2010-01-27 13:32 com.android.email
...
2010/9/27追記:
openの際に O_CREAT が指定されている場合にはmode(ファイルパーミション)指定が必要のため追加