FileObserver.java revision 60d8762413e8daba5f73559786312a9ec5e3b827
1/* 2 * Copyright (C) 2006 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package android.os; 18 19import android.util.Log; 20 21import com.android.internal.os.RuntimeInit; 22 23import java.lang.ref.WeakReference; 24import java.util.ArrayList; 25import java.util.HashMap; 26 27public abstract class FileObserver { 28 /** File was accessed */ 29 public static final int ACCESS = 0x00000001; 30 /** File was modified */ 31 public static final int MODIFY = 0x00000002; 32 /** Metadata changed */ 33 public static final int ATTRIB = 0x00000004; 34 /** Writable file was closed */ 35 public static final int CLOSE_WRITE = 0x00000008; 36 /** Unwrittable file closed */ 37 public static final int CLOSE_NOWRITE = 0x00000010; 38 /** File was opened */ 39 public static final int OPEN = 0x00000020; 40 /** File was moved from X */ 41 public static final int MOVED_FROM = 0x00000040; 42 /** File was moved to Y */ 43 public static final int MOVED_TO = 0x00000080; 44 /** Subfile was created */ 45 public static final int CREATE = 0x00000100; 46 /** Subfile was deleted */ 47 public static final int DELETE = 0x00000200; 48 /** Self was deleted */ 49 public static final int DELETE_SELF = 0x00000400; 50 /** Self was moved */ 51 public static final int MOVE_SELF = 0x00000800; 52 53 public static final int ALL_EVENTS = ACCESS | MODIFY | ATTRIB | CLOSE_WRITE 54 | CLOSE_NOWRITE | OPEN | MOVED_FROM | MOVED_TO | DELETE | CREATE 55 | DELETE_SELF | MOVE_SELF; 56 57 private static final String LOG_TAG = "FileObserver"; 58 59 private static class ObserverThread extends Thread { 60 private HashMap<Integer, WeakReference> m_observers = new HashMap<Integer, WeakReference>(); 61 private int m_fd; 62 63 public ObserverThread() { 64 super("FileObserver"); 65 m_fd = init(); 66 } 67 68 public void run() { 69 observe(m_fd); 70 } 71 72 public int startWatching(String path, int mask, FileObserver observer) { 73 int wfd = startWatching(m_fd, path, mask); 74 75 Integer i = new Integer(wfd); 76 if (wfd >= 0) { 77 synchronized (m_observers) { 78 m_observers.put(i, new WeakReference(observer)); 79 } 80 } 81 82 return i; 83 } 84 85 public void stopWatching(int descriptor) { 86 stopWatching(m_fd, descriptor); 87 } 88 89 public void onEvent(int wfd, int mask, String path) { 90 // look up our observer, fixing up the map if necessary... 91 FileObserver observer; 92 93 synchronized (m_observers) { 94 WeakReference weak = m_observers.get(wfd); 95 observer = (FileObserver) weak.get(); 96 if (observer == null) { 97 m_observers.remove(wfd); 98 } 99 } 100 101 // ...then call out to the observer without the sync lock held 102 if (observer != null) { 103 try { 104 observer.onEvent(mask, path); 105 } catch (Throwable throwable) { 106 Log.wtf(LOG_TAG, "Unhandled exception in FileObserver " + observer, throwable); 107 } 108 } 109 } 110 111 private native int init(); 112 private native void observe(int fd); 113 private native int startWatching(int fd, String path, int mask); 114 private native void stopWatching(int fd, int wfd); 115 } 116 117 private static ObserverThread s_observerThread; 118 119 static { 120 s_observerThread = new ObserverThread(); 121 s_observerThread.start(); 122 } 123 124 // instance 125 private String m_path; 126 private Integer m_descriptor; 127 private int m_mask; 128 129 public FileObserver(String path) { 130 this(path, ALL_EVENTS); 131 } 132 133 public FileObserver(String path, int mask) { 134 m_path = path; 135 m_mask = mask; 136 m_descriptor = -1; 137 } 138 139 protected void finalize() { 140 stopWatching(); 141 } 142 143 public void startWatching() { 144 if (m_descriptor < 0) { 145 m_descriptor = s_observerThread.startWatching(m_path, m_mask, this); 146 } 147 } 148 149 public void stopWatching() { 150 if (m_descriptor >= 0) { 151 s_observerThread.stopWatching(m_descriptor); 152 m_descriptor = -1; 153 } 154 } 155 156 public abstract void onEvent(int event, String path); 157} 158