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 17 package android.os; 18 19 import android.util.Log; 20 21 import com.android.internal.os.RuntimeInit; 22 23 import java.lang.ref.WeakReference; 24 import java.util.ArrayList; 25 import java.util.HashMap; 26 27 public 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 ObserverThread()63 public ObserverThread() { 64 super("FileObserver"); 65 m_fd = init(); 66 } 67 run()68 public void run() { 69 observe(m_fd); 70 } 71 startWatching(String path, int mask, FileObserver observer)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 stopWatching(int descriptor)85 public void stopWatching(int descriptor) { 86 stopWatching(m_fd, descriptor); 87 } 88 onEvent(int wfd, int mask, String path)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.e(LOG_TAG, "Unhandled throwable " + throwable.toString() + 107 " (returned by observer " + observer + ")", throwable); 108 RuntimeInit.crash("FileObserver", throwable); 109 } 110 } 111 } 112 init()113 private native int init(); observe(int fd)114 private native void observe(int fd); startWatching(int fd, String path, int mask)115 private native int startWatching(int fd, String path, int mask); stopWatching(int fd, int wfd)116 private native void stopWatching(int fd, int wfd); 117 } 118 119 private static ObserverThread s_observerThread; 120 121 static { 122 s_observerThread = new ObserverThread(); s_observerThread.start()123 s_observerThread.start(); 124 } 125 126 // instance 127 private String m_path; 128 private Integer m_descriptor; 129 private int m_mask; 130 FileObserver(String path)131 public FileObserver(String path) { 132 this(path, ALL_EVENTS); 133 } 134 FileObserver(String path, int mask)135 public FileObserver(String path, int mask) { 136 m_path = path; 137 m_mask = mask; 138 m_descriptor = -1; 139 } 140 finalize()141 protected void finalize() { 142 stopWatching(); 143 } 144 startWatching()145 public void startWatching() { 146 if (m_descriptor < 0) { 147 m_descriptor = s_observerThread.startWatching(m_path, m_mask, this); 148 } 149 } 150 stopWatching()151 public void stopWatching() { 152 if (m_descriptor >= 0) { 153 s_observerThread.stopWatching(m_descriptor); 154 m_descriptor = -1; 155 } 156 } 157 onEvent(int event, String path)158 public abstract void onEvent(int event, String path); 159 } 160