• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
UEvent(String message)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 
get(String key)68         public String get(String key) {
69             return mMap.get(key);
70         }
71 
get(String key, String defaultValue)72         public String get(String key, String defaultValue) {
73             String result = mMap.get(key);
74             return (result == null ? defaultValue : result);
75         }
76 
toString()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 
UEventThread()92         UEventThread() {
93             super("UEventObserver");
94         }
95 
run()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         }
addObserver(String match, UEventObserver observer)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 */
removeObserver(UEventObserver observer)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 
native_setup()141     private static native void native_setup();
next_event(byte[] buffer)142     private static native int next_event(byte[] buffer);
143 
ensureThreadStarted()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      */
startObserving(String match)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      */
stopObserving()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      */
onUEvent(UEvent event)182     public abstract void onUEvent(UEvent event);
183 
finalize()184     protected void finalize() throws Throwable {
185         try {
186             stopObserving();
187         } finally {
188             super.finalize();
189         }
190     }
191 }
192