UEventObserver.java revision 008b1762a8d5c908281a832ff90817ade6c7f9f6
1/* 2 * Copyright (C) 2008 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 java.util.ArrayList; 20import java.util.HashMap; 21 22/** 23 * UEventObserver is an abstract class that receives UEvent's from the kernel.<p> 24 * 25 * Subclass UEventObserver, implementing onUEvent(UEvent event), then call 26 * startObserving() with a match string. The UEvent thread will then call your 27 * onUEvent() method when a UEvent occurs that contains your match string.<p> 28 * 29 * Call stopObserving() to stop receiving UEvent's.<p> 30 * 31 * There is only one UEvent thread per process, even if that process has 32 * multiple UEventObserver subclass instances. The UEvent thread starts when 33 * the startObserving() is called for the first time in that process. Once 34 * started the UEvent thread will not stop (although it can stop notifying 35 * UEventObserver's via stopObserving()).<p> 36 * 37 * @hide 38*/ 39public abstract class UEventObserver { 40 private static UEventThread sThread; 41 42 private static native void native_setup(); 43 private static native int next_event(byte[] buffer); 44 45 public UEventObserver() { 46 } 47 48 protected void finalize() throws Throwable { 49 try { 50 stopObserving(); 51 } finally { 52 super.finalize(); 53 } 54 } 55 56 private static UEventThread getThread() { 57 synchronized (UEventObserver.class) { 58 if (sThread == null) { 59 sThread = new UEventThread(); 60 sThread.start(); 61 } 62 return sThread; 63 } 64 } 65 66 private static UEventThread peekThread() { 67 synchronized (UEventObserver.class) { 68 return sThread; 69 } 70 } 71 72 /** 73 * Begin observation of UEvent's.<p> 74 * This method will cause the UEvent thread to start if this is the first 75 * invocation of startObserving in this process.<p> 76 * Once called, the UEvent thread will call onUEvent() when an incoming 77 * UEvent matches the specified string.<p> 78 * This method can be called multiple times to register multiple matches. 79 * Only one call to stopObserving is required even with multiple registered 80 * matches. 81 * @param match A substring of the UEvent to match. Use "" to match all 82 * UEvent's 83 */ 84 public final void startObserving(String match) { 85 final UEventThread t = getThread(); 86 t.addObserver(match, this); 87 } 88 89 /** 90 * End observation of UEvent's.<p> 91 * This process's UEvent thread will never call onUEvent() on this 92 * UEventObserver after this call. Repeated calls have no effect. 93 */ 94 public final void stopObserving() { 95 final UEventThread t = getThread(); 96 if (t != null) { 97 t.removeObserver(this); 98 } 99 } 100 101 /** 102 * Subclasses of UEventObserver should override this method to handle 103 * UEvents. 104 */ 105 public abstract void onUEvent(UEvent event); 106 107 /** 108 * Representation of a UEvent. 109 */ 110 public static final class UEvent { 111 // collection of key=value pairs parsed from the uevent message 112 private final HashMap<String,String> mMap = new HashMap<String,String>(); 113 114 public UEvent(String message) { 115 int offset = 0; 116 int length = message.length(); 117 118 while (offset < length) { 119 int equals = message.indexOf('=', offset); 120 int at = message.indexOf(0, offset); 121 if (at < 0) break; 122 123 if (equals > offset && equals < at) { 124 // key is before the equals sign, and value is after 125 mMap.put(message.substring(offset, equals), 126 message.substring(equals + 1, at)); 127 } 128 129 offset = at + 1; 130 } 131 } 132 133 public String get(String key) { 134 return mMap.get(key); 135 } 136 137 public String get(String key, String defaultValue) { 138 String result = mMap.get(key); 139 return (result == null ? defaultValue : result); 140 } 141 142 public String toString() { 143 return mMap.toString(); 144 } 145 } 146 147 private static final class UEventThread extends Thread { 148 /** Many to many mapping of string match to observer. 149 * Multimap would be better, but not available in android, so use 150 * an ArrayList where even elements are the String match and odd 151 * elements the corresponding UEventObserver observer */ 152 private final ArrayList<Object> mKeysAndObservers = new ArrayList<Object>(); 153 154 private final ArrayList<UEventObserver> mTempObserversToSignal = 155 new ArrayList<UEventObserver>(); 156 157 public UEventThread() { 158 super("UEventObserver"); 159 } 160 161 public void run() { 162 native_setup(); 163 164 byte[] buffer = new byte[1024]; 165 int len; 166 while (true) { 167 len = next_event(buffer); 168 if (len > 0) { 169 sendEvent(new String(buffer, 0, len)); 170 } 171 } 172 } 173 174 private void sendEvent(String message) { 175 synchronized (mKeysAndObservers) { 176 final int N = mKeysAndObservers.size(); 177 for (int i = 0; i < N; i += 2) { 178 final String key = (String)mKeysAndObservers.get(i); 179 if (message.indexOf(key) != -1) { 180 final UEventObserver observer = 181 (UEventObserver)mKeysAndObservers.get(i + 1); 182 mTempObserversToSignal.add(observer); 183 } 184 } 185 } 186 187 if (!mTempObserversToSignal.isEmpty()) { 188 final UEvent event = new UEvent(message); 189 final int N = mTempObserversToSignal.size(); 190 for (int i = 0; i < N; i++) { 191 final UEventObserver observer = mTempObserversToSignal.get(i); 192 observer.onUEvent(event); 193 } 194 mTempObserversToSignal.clear(); 195 } 196 } 197 198 public void addObserver(String match, UEventObserver observer) { 199 synchronized (mKeysAndObservers) { 200 mKeysAndObservers.add(match); 201 mKeysAndObservers.add(observer); 202 } 203 } 204 205 /** Removes every key/value pair where value=observer from mObservers */ 206 public void removeObserver(UEventObserver observer) { 207 synchronized (mKeysAndObservers) { 208 for (int i = 0; i < mKeysAndObservers.size(); ) { 209 if (mKeysAndObservers.get(i + 1) == observer) { 210 mKeysAndObservers.remove(i + 1); 211 mKeysAndObservers.remove(i); 212 } else { 213 i += 2; 214 } 215 } 216 } 217 } 218 } 219} 220