OSDN Git Service

Fix a FileObserver jni bug.
authorEvan JIANG <firstfan@gmail.com>
Mon, 27 Oct 2008 17:13:38 +0000 (01:13 +0800)
committerJean-Baptiste Queru <jbq@google.com>
Wed, 4 Mar 2009 20:04:07 +0000 (12:04 -0800)
The path string in FileObserver jni will not be automatically released
in the while loop. Then it will cause too many local refs in the ref
table. When received too many file changed notifications/events, the
process will be killed for "Failed adding to JNI local ref table".
Test code:
=============================================================
import android.app.Activity;
import android.os.Bundle;
import android.os.FileObserver;
import android.util.Log;

import java.io.File;
import java.io.IOException;

public class TestApp extends Activity {

    public static final String TAG="TestApp";
    FileObserver observer;

    @Override
    public void onCreate(Bundle icicle) {
        super.onCreate(icicle);
        setContentView(R.layout.main);

        observer=new FileObserver("/tmp"){
            @Override
            public void onEvent(int event, String path) {
                if(event == FileObserver.CREATE){
                    Log.e(TAG, "File created [" + path + "]");
                }else if(event == FileObserver.DELETE){
                    Log.e(TAG, "File deleted [" + path + "]");
                }
            }
        };
        observer.startWatching();

        File f=new File("/tmp/a.txt");
        for (int i=0;i<300;i++) {
            try {
                f.createNewFile();
            } catch (IOException e) {
            }
            f.delete();
        }
    }

}
================================================
The last 2 lines of the log:
E/dalvikvm(  705): Failed adding to JNI local ref table (has 512
entries)
E/dalvikvm(  705): VM aborting

core/jni/android_util_FileObserver.cpp

index 794478a..13a1645 100644 (file)
@@ -84,6 +84,10 @@ static void android_os_fileobserver_observe(JNIEnv* env, jobject object, jint fd
             }
             
                    env->CallVoidMethod(object, method_onEvent, event->wd, event->mask, path);
+            if (path != NULL)
+            {
+                env->DeleteLocalRef(path);
+            }
                    
                    event_size = sizeof(*event) + event->len;
                        num_bytes -= event_size;