Home | History | Annotate | Download | only in os
      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 
     17 package android.os;
     18 
     19 import java.util.ArrayList;
     20 import 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 */
     39 public abstract class UEventObserver {
     40     private static final String TAG = UEventObserver.class.getSimpleName();
     41 
     42     /**
     43      * Representation of a UEvent.
     44      */
     45     static public class UEvent {
     46         // collection of key=value pairs parsed from the uevent message
     47         public HashMap<String,String> mMap = new HashMap<String,String>();
     48 
     49         public UEvent(String message) {
     50             int offset = 0;
     51             int length = message.length();
     52 
     53             while (offset < length) {
     54                 int equals = message.indexOf('=', offset);
     55                 int at = message.indexOf(0, offset);
     56                 if (at < 0) break;
     57 
     58                 if (equals > offset && equals < at) {
     59                     // key is before the equals sign, and value is after
     60                     mMap.put(message.substring(offset, equals),
     61                             message.substring(equals + 1, at));
     62                 }
     63 
     64                 offset = at + 1;
     65             }
     66         }
     67 
     68         public String get(String key) {
     69             return mMap.get(key);
     70         }
     71 
     72         public String get(String key, String defaultValue) {
     73             String result = mMap.get(key);
     74             return (result == null ? defaultValue : result);
     75         }
     76 
     77         public String toString() {
     78             return mMap.toString();
     79         }
     80     }
     81 
     82     private static UEventThread sThread;
     83     private static boolean sThreadStarted = false;
     84 
     85     private static class UEventThread extends Thread {
     86         /** Many to many mapping of string match to observer.
     87          *  Multimap would be better, but not available in android, so use
     88          *  an ArrayList where even elements are the String match and odd
     89          *  elements the corresponding UEventObserver observer */
     90         private ArrayList<Object> mObservers = new ArrayList<Object>();
     91 
     92         UEventThread() {
     93             super("UEventObserver");
     94         }
     95 
     96         public void run() {
     97             native_setup();
     98 
     99             byte[] buffer = new byte[1024];
    100             int len;
    101             while (true) {
    102                 len = next_event(buffer);
    103                 if (len > 0) {
    104                     String bufferStr = new String(buffer, 0, len);  // easier to search a String
    105                     synchronized (mObservers) {
    106                         for (int i = 0; i < mObservers.size(); i += 2) {
    107                             if (bufferStr.indexOf((String)mObservers.get(i)) != -1) {
    108                                 ((UEventObserver)mObservers.get(i+1))
    109                                         .onUEvent(new UEvent(bufferStr));
    110                             }
    111                         }
    112                     }
    113                 }
    114             }
    115         }
    116         public void addObserver(String match, UEventObserver observer) {
    117             synchronized(mObservers) {
    118                 mObservers.add(match);
    119                 mObservers.add(observer);
    120             }
    121         }
    122         /** Removes every key/value pair where value=observer from mObservers */
    123         public void removeObserver(UEventObserver observer) {
    124             synchronized(mObservers) {
    125                 boolean found = true;
    126                 while (found) {
    127                     found = false;
    128                     for (int i = 0; i < mObservers.size(); i += 2) {
    129                         if (mObservers.get(i+1) == observer) {
    130                             mObservers.remove(i+1);
    131                             mObservers.remove(i);
    132                             found = true;
    133                             break;
    134                         }
    135                     }
    136                 }
    137             }
    138         }
    139     }
    140 
    141     private static native void native_setup();
    142     private static native int next_event(byte[] buffer);
    143 
    144     private static final synchronized void ensureThreadStarted() {
    145         if (sThreadStarted == false) {
    146             sThread = new UEventThread();
    147             sThread.start();
    148             sThreadStarted = true;
    149         }
    150     }
    151 
    152     /**
    153      * Begin observation of UEvent's.<p>
    154      * This method will cause the UEvent thread to start if this is the first
    155      * invocation of startObserving in this process.<p>
    156      * Once called, the UEvent thread will call onUEvent() when an incoming
    157      * UEvent matches the specified string.<p>
    158      * This method can be called multiple times to register multiple matches.
    159      * Only one call to stopObserving is required even with multiple registered
    160      * matches.
    161      * @param match A substring of the UEvent to match. Use "" to match all
    162      *              UEvent's
    163      */
    164     public final synchronized void startObserving(String match) {
    165         ensureThreadStarted();
    166         sThread.addObserver(match, this);
    167     }
    168 
    169     /**
    170      * End observation of UEvent's.<p>
    171      * This process's UEvent thread will never call onUEvent() on this
    172      * UEventObserver after this call. Repeated calls have no effect.
    173      */
    174     public final synchronized void stopObserving() {
    175         sThread.removeObserver(this);
    176     }
    177 
    178     /**
    179      * Subclasses of UEventObserver should override this method to handle
    180      * UEvents.
    181      */
    182     public abstract void onUEvent(UEvent event);
    183 
    184     protected void finalize() throws Throwable {
    185         try {
    186             stopObserving();
    187         } finally {
    188             super.finalize();
    189         }
    190     }
    191 }
    192