19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/* 29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2008 The Android Open Source Project 39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); 59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License. 69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at 79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software 119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, 129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and 149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License. 159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpackage android.os; 189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.ArrayList; 209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.HashMap; 219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/** 239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * UEventObserver is an abstract class that receives UEvent's from the kernel.<p> 249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Subclass UEventObserver, implementing onUEvent(UEvent event), then call 269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * startObserving() with a match string. The UEvent thread will then call your 279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * onUEvent() method when a UEvent occurs that contains your match string.<p> 289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Call stopObserving() to stop receiving UEvent's.<p> 309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * There is only one UEvent thread per process, even if that process has 329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * multiple UEventObserver subclass instances. The UEvent thread starts when 339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * the startObserving() is called for the first time in that process. Once 349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * started the UEvent thread will not stop (although it can stop notifying 359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * UEventObserver's via stopObserving()).<p> 369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @hide 389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project*/ 399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpublic abstract class UEventObserver { 409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final String TAG = UEventObserver.class.getSimpleName(); 419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Representation of a UEvent. 449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project static public class UEvent { 469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // collection of key=value pairs parsed from the uevent message 479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public HashMap<String,String> mMap = new HashMap<String,String>(); 489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public UEvent(String message) { 509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int offset = 0; 519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int length = message.length(); 529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project while (offset < length) { 549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int equals = message.indexOf('=', offset); 559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int at = message.indexOf(0, offset); 569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (at < 0) break; 579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (equals > offset && equals < at) { 599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // key is before the equals sign, and value is after 609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMap.put(message.substring(offset, equals), 619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project message.substring(equals + 1, at)); 629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project offset = at + 1; 659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public String get(String key) { 699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mMap.get(key); 709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public String get(String key, String defaultValue) { 739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String result = mMap.get(key); 749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return (result == null ? defaultValue : result); 759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public String toString() { 789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mMap.toString(); 799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static UEventThread sThread; 839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static boolean sThreadStarted = false; 849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static class UEventThread extends Thread { 869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** Many to many mapping of string match to observer. 879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Multimap would be better, but not available in android, so use 889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * an ArrayList where even elements are the String match and odd 899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * elements the corresponding UEventObserver observer */ 909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private ArrayList<Object> mObservers = new ArrayList<Object>(); 919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project UEventThread() { 939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project super("UEventObserver"); 949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void run() { 979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project native_setup(); 989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project byte[] buffer = new byte[1024]; 1009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int len; 1019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project while (true) { 1029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project len = next_event(buffer); 1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (len > 0) { 1049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String bufferStr = new String(buffer, 0, len); // easier to search a String 1059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project synchronized (mObservers) { 1069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < mObservers.size(); i += 2) { 1079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (bufferStr.indexOf((String)mObservers.get(i)) != -1) { 1089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ((UEventObserver)mObservers.get(i+1)) 1099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project .onUEvent(new UEvent(bufferStr)); 1109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void addObserver(String match, UEventObserver observer) { 1179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project synchronized(mObservers) { 1189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mObservers.add(match); 1199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mObservers.add(observer); 1209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** Removes every key/value pair where value=observer from mObservers */ 1239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void removeObserver(UEventObserver observer) { 1249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project synchronized(mObservers) { 1259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean found = true; 1269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project while (found) { 1279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project found = false; 1289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < mObservers.size(); i += 2) { 1299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mObservers.get(i+1) == observer) { 1309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mObservers.remove(i+1); 1319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mObservers.remove(i); 1329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project found = true; 1339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 1349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static native void native_setup(); 1429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static native int next_event(byte[] buffer); 1439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final synchronized void ensureThreadStarted() { 1459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (sThreadStarted == false) { 1469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sThread = new UEventThread(); 1479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sThread.start(); 1489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sThreadStarted = true; 1499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Begin observation of UEvent's.<p> 1549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * This method will cause the UEvent thread to start if this is the first 1559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * invocation of startObserving in this process.<p> 1569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Once called, the UEvent thread will call onUEvent() when an incoming 1579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * UEvent matches the specified string.<p> 1589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * This method can be called multiple times to register multiple matches. 1599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Only one call to stopObserving is required even with multiple registered 1609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * matches. 1619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param match A substring of the UEvent to match. Use "" to match all 1629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * UEvent's 1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public final synchronized void startObserving(String match) { 1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ensureThreadStarted(); 1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sThread.addObserver(match, this); 1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * End observation of UEvent's.<p> 1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * This process's UEvent thread will never call onUEvent() on this 1729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * UEventObserver after this call. Repeated calls have no effect. 1739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public final synchronized void stopObserving() { 1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sThread.removeObserver(this); 1769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Subclasses of UEventObserver should override this method to handle 1809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * UEvents. 1819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public abstract void onUEvent(UEvent event); 1839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project protected void finalize() throws Throwable { 1859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 1869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project stopObserving(); 1879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } finally { 1889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project super.finalize(); 1899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 192