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 public static final int ACCESS = 0x00000001; /* File was accessed */ 29 public static final int MODIFY = 0x00000002; /* File was modified */ 30 public static final int ATTRIB = 0x00000004; /* Metadata changed */ 31 public static final int CLOSE_WRITE = 0x00000008; /* Writtable file was closed */ 32 public static final int CLOSE_NOWRITE = 0x00000010; /* Unwrittable file closed */ 33 public static final int OPEN = 0x00000020; /* File was opened */ 34 public static final int MOVED_FROM = 0x00000040; /* File was moved from X */ 35 public static final int MOVED_TO = 0x00000080; /* File was moved to Y */ 36 public static final int CREATE = 0x00000100; /* Subfile was created */ 37 public static final int DELETE = 0x00000200; /* Subfile was deleted */ 38 public static final int DELETE_SELF = 0x00000400; /* Self was deleted */ 39 public static final int MOVE_SELF = 0x00000800; /* Self was moved */ 40 public static final int ALL_EVENTS = ACCESS | MODIFY | ATTRIB | CLOSE_WRITE 41 | CLOSE_NOWRITE | OPEN | MOVED_FROM | MOVED_TO | DELETE | CREATE 42 | DELETE_SELF | MOVE_SELF; 43 44 private static final String LOG_TAG = "FileObserver"; 45 46 private static class ObserverThread extends Thread { 47 private HashMap<Integer, WeakReference> m_observers = new HashMap<Integer, WeakReference>(); 48 private int m_fd; 49 50 public ObserverThread() { 51 super("FileObserver"); 52 m_fd = init(); 53 } 54 55 public void run() { 56 observe(m_fd); 57 } 58 59 public int startWatching(String path, int mask, FileObserver observer) { 60 int wfd = startWatching(m_fd, path, mask); 61 62 Integer i = new Integer(wfd); 63 if (wfd >= 0) { 64 synchronized (m_observers) { 65 m_observers.put(i, new WeakReference(observer)); 66 } 67 } 68 69 return i; 70 } 71 72 public void stopWatching(int descriptor) { 73 stopWatching(m_fd, descriptor); 74 } 75 76 public void onEvent(int wfd, int mask, String path) { 77 // look up our observer, fixing up the map if necessary... 78 FileObserver observer; 79 80 synchronized (m_observers) { 81 WeakReference weak = m_observers.get(wfd); 82 observer = (FileObserver) weak.get(); 83 if (observer == null) { 84 m_observers.remove(wfd); 85 } 86 } 87 88 // ...then call out to the observer without the sync lock held 89 if (observer != null) { 90 try { 91 observer.onEvent(mask, path); 92 } catch (Throwable throwable) { 93 Log.e(LOG_TAG, "Unhandled throwable " + throwable.toString() + 94 " (returned by observer " + observer + ")", throwable); 95 RuntimeInit.crash("FileObserver", throwable); 96 } 97 } 98 } 99 100 private native int init(); 101 private native void observe(int fd); 102 private native int startWatching(int fd, String path, int mask); 103 private native void stopWatching(int fd, int wfd); 104 } 105 106 private static ObserverThread s_observerThread; 107 108 static { 109 s_observerThread = new ObserverThread(); 110 s_observerThread.start(); 111 } 112 113 // instance 114 private String m_path; 115 private Integer m_descriptor; 116 private int m_mask; 117 118 public FileObserver(String path) { 119 this(path, ALL_EVENTS); 120 } 121 122 public FileObserver(String path, int mask) { 123 m_path = path; 124 m_mask = mask; 125 m_descriptor = -1; 126 } 127 128 protected void finalize() { 129 stopWatching(); 130 } 131 132 public void startWatching() { 133 if (m_descriptor < 0) { 134 m_descriptor = s_observerThread.startWatching(m_path, m_mask, this); 135 } 136 } 137 138 public void stopWatching() { 139 if (m_descriptor >= 0) { 140 s_observerThread.stopWatching(m_descriptor); 141 m_descriptor = -1; 142 } 143 } 144 145 public abstract void onEvent(int event, String path); 146} 147