OSDN Git Service

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