Skip to content

Commit 892f371

Browse files
Jeff BrownAndroid (Google) Code Review
authored andcommitted
Merge "Encapsulate locks in UEventObservers." into jb-mr1-dev
2 parents 4b72463 + 008b176 commit 892f371

File tree

3 files changed

+386
-348
lines changed

3 files changed

+386
-348
lines changed

core/java/android/os/UEventObserver.java

Lines changed: 112 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -37,14 +37,79 @@
3737
* @hide
3838
*/
3939
public abstract class UEventObserver {
40-
private static final String TAG = UEventObserver.class.getSimpleName();
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);
41106

42107
/**
43108
* Representation of a UEvent.
44109
*/
45-
static public class UEvent {
110+
public static final class UEvent {
46111
// collection of key=value pairs parsed from the uevent message
47-
public HashMap<String,String> mMap = new HashMap<String,String>();
112+
private final HashMap<String,String> mMap = new HashMap<String,String>();
48113

49114
public UEvent(String message) {
50115
int offset = 0;
@@ -79,20 +144,20 @@ public String toString() {
79144
}
80145
}
81146

82-
private static UEventThread sThread;
83-
private static boolean sThreadStarted = false;
84-
85-
private static class UEventThread extends Thread {
147+
private static final class UEventThread extends Thread {
86148
/** Many to many mapping of string match to observer.
87149
* Multimap would be better, but not available in android, so use
88150
* an ArrayList where even elements are the String match and odd
89151
* elements the corresponding UEventObserver observer */
90-
private ArrayList<Object> mObservers = new ArrayList<Object>();
91-
92-
UEventThread() {
152+
private final ArrayList<Object> mKeysAndObservers = new ArrayList<Object>();
153+
154+
private final ArrayList<UEventObserver> mTempObserversToSignal =
155+
new ArrayList<UEventObserver>();
156+
157+
public UEventThread() {
93158
super("UEventObserver");
94159
}
95-
160+
96161
public void run() {
97162
native_setup();
98163

@@ -101,91 +166,54 @@ public void run() {
101166
while (true) {
102167
len = next_event(buffer);
103168
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-
}
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);
112183
}
113184
}
114185
}
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+
}
115196
}
197+
116198
public void addObserver(String match, UEventObserver observer) {
117-
synchronized(mObservers) {
118-
mObservers.add(match);
119-
mObservers.add(observer);
199+
synchronized (mKeysAndObservers) {
200+
mKeysAndObservers.add(match);
201+
mKeysAndObservers.add(observer);
120202
}
121203
}
204+
122205
/** Removes every key/value pair where value=observer from mObservers */
123206
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-
}
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;
135214
}
136215
}
137216
}
138217
}
139218
}
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-
}
191219
}

0 commit comments

Comments
 (0)