blob: 3355ee33d4867d343a1bf948351ad263929533c6 [file] [log] [blame]
John Grossman37237832012-01-12 11:05:37 -08001/*
2 * Copyright (C) 2012 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 */
16package android.os;
17
18import java.net.InetAddress;
19import java.net.InetSocketAddress;
20import java.util.NoSuchElementException;
21
22import android.os.CommonTimeUtils;
23import android.os.IBinder;
24import android.os.RemoteException;
25import android.os.ServiceManager;
26
27/**
28 * Used for configuring and controlling the status of the android common time service.
29 * @hide
30 */
31public class CommonTimeConfig {
32 /**
33 * Successful operation.
34 */
35 public static final int SUCCESS = 0;
36 /**
37 * Unspecified error.
38 */
39 public static final int ERROR = -1;
40 /**
41 * Operation failed due to bad parameter value.
42 */
43 public static final int ERROR_BAD_VALUE = -4;
44 /**
45 * Operation failed due to dead remote object.
46 */
47 public static final int ERROR_DEAD_OBJECT = -7;
48
49 /**
50 * Sentinel value returned by {@link #getMasterElectionGroupId()} when an error occurs trying to
51 * fetch the master election group.
52 */
53 public static final long INVALID_GROUP_ID = -1;
54
55 /**
56 * Name of the underlying native binder service
57 */
58 public static final String SERVICE_NAME = "common_time.config";
59
60 /**
61 * Class constructor.
62 * @throws android.os.RemoteException
63 */
64 public CommonTimeConfig()
65 throws RemoteException {
66 mRemote = ServiceManager.getService(SERVICE_NAME);
67 if (null == mRemote)
68 throw new RemoteException();
69
70 mInterfaceDesc = mRemote.getInterfaceDescriptor();
71 mUtils = new CommonTimeUtils(mRemote, mInterfaceDesc);
72 mRemote.linkToDeath(mDeathHandler, 0);
73 }
74
75 /**
76 * Handy class factory method.
77 */
78 static public CommonTimeConfig create() {
79 CommonTimeConfig retVal;
80
81 try {
82 retVal = new CommonTimeConfig();
83 }
84 catch (RemoteException e) {
85 retVal = null;
86 }
87
88 return retVal;
89 }
90
91 /**
92 * Release all native resources held by this {@link android.os.CommonTimeConfig} instance. Once
93 * resources have been released, the {@link android.os.CommonTimeConfig} instance is
94 * disconnected from the native service and will throw a {@link android.os.RemoteException} if
95 * any of its methods are called. Clients should always call release on their client instances
96 * before releasing their last Java reference to the instance. Failure to do this will cause
97 * non-deterministic native resource reclamation and may cause the common time service to remain
98 * active on the network for longer than it should.
99 */
100 public void release() {
101 if (null != mRemote) {
102 try {
103 mRemote.unlinkToDeath(mDeathHandler, 0);
104 }
105 catch (NoSuchElementException e) { }
106 mRemote = null;
107 }
108 mUtils = null;
109 }
110
111 /**
112 * Gets the current priority of the common time service used in the master election protocol.
113 *
114 * @return an 8 bit value indicating the priority of this common time service relative to other
115 * common time services operating in the same domain.
116 * @throws android.os.RemoteException
117 */
118 public byte getMasterElectionPriority()
119 throws RemoteException {
120 throwOnDeadServer();
121 return (byte)mUtils.transactGetInt(METHOD_GET_MASTER_ELECTION_PRIORITY, -1);
122 }
123
124 /**
125 * Sets the current priority of the common time service used in the master election protocol.
126 *
127 * @param priority priority of the common time service used in the master election protocol.
128 * Lower numbers are lower priority.
129 * @return {@link #SUCCESS} in case of success,
130 * {@link #ERROR} or {@link #ERROR_DEAD_OBJECT} in case of failure.
131 */
132 public int setMasterElectionPriority(byte priority) {
133 if (checkDeadServer())
134 return ERROR_DEAD_OBJECT;
135 return mUtils.transactSetInt(METHOD_SET_MASTER_ELECTION_PRIORITY, priority);
136 }
137
138 /**
139 * Gets the IP endpoint used by the time service to participate in the master election protocol.
140 *
141 * @return an InetSocketAddress containing the IP address and UDP port being used by the
142 * system's common time service to participate in the master election protocol.
143 * @throws android.os.RemoteException
144 */
145 public InetSocketAddress getMasterElectionEndpoint()
146 throws RemoteException {
147 throwOnDeadServer();
148 return mUtils.transactGetSockaddr(METHOD_GET_MASTER_ELECTION_ENDPOINT);
149 }
150
151 /**
152 * Sets the IP endpoint used by the common time service to participate in the master election
153 * protocol.
154 *
155 * @param ep The IP address and UDP port to be used by the common time service to participate in
156 * the master election protocol. The supplied IP address must be either the broadcast or
157 * multicast address, unicast addresses are considered to be illegal values.
158 * @return {@link #SUCCESS} in case of success,
159 * {@link #ERROR}, {@link #ERROR_BAD_VALUE} or {@link #ERROR_DEAD_OBJECT} in case of failure.
160 */
161 public int setMasterElectionEndpoint(InetSocketAddress ep) {
162 if (checkDeadServer())
163 return ERROR_DEAD_OBJECT;
164 return mUtils.transactSetSockaddr(METHOD_SET_MASTER_ELECTION_ENDPOINT, ep);
165 }
166
167 /**
168 * Gets the current group ID used by the common time service in the master election protocol.
169 *
170 * @return The 64-bit group ID of the common time service.
171 * @throws android.os.RemoteException
172 */
173 public long getMasterElectionGroupId()
174 throws RemoteException {
175 throwOnDeadServer();
176 return mUtils.transactGetLong(METHOD_GET_MASTER_ELECTION_GROUP_ID, INVALID_GROUP_ID);
177 }
178
179 /**
180 * Sets the current group ID used by the common time service in the master election protocol.
181 *
182 * @param id The 64-bit group ID of the common time service.
183 * @return {@link #SUCCESS} in case of success,
184 * {@link #ERROR}, {@link #ERROR_BAD_VALUE} or {@link #ERROR_DEAD_OBJECT} in case of failure.
185 */
186 public int setMasterElectionGroupId(long id) {
187 if (checkDeadServer())
188 return ERROR_DEAD_OBJECT;
189 return mUtils.transactSetLong(METHOD_SET_MASTER_ELECTION_GROUP_ID, id);
190 }
191
192 /**
193 * Gets the name of the network interface which the common time service attempts to bind to.
194 *
195 * @return a string with the network interface name which the common time service is bound to,
196 * or null if the service is currently unbound. Examples of interface names are things like
197 * "eth0", or "wlan0".
198 * @throws android.os.RemoteException
199 */
200 public String getInterfaceBinding()
201 throws RemoteException {
202 throwOnDeadServer();
203
204 String ifaceName = mUtils.transactGetString(METHOD_GET_INTERFACE_BINDING, null);
205
206 if ((null != ifaceName) && (0 == ifaceName.length()))
207 return null;
208
209 return ifaceName;
210 }
211
212 /**
213 * Sets the name of the network interface which the common time service should attempt to bind
214 * to.
215 *
216 * @param ifaceName The name of the network interface ("eth0", "wlan0", etc...) wich the common
217 * time service should attempt to bind to, or null to force the common time service to unbind
218 * from the network and run in networkless mode.
219 * @return {@link #SUCCESS} in case of success,
220 * {@link #ERROR}, {@link #ERROR_BAD_VALUE} or {@link #ERROR_DEAD_OBJECT} in case of failure.
221 */
222 public int setNetworkBinding(String ifaceName) {
223 if (checkDeadServer())
224 return ERROR_DEAD_OBJECT;
225
226 return mUtils.transactSetString(METHOD_SET_INTERFACE_BINDING,
227 (null == ifaceName) ? "" : ifaceName);
228 }
229
230 /**
231 * Gets the amount of time the common time service will wait between master announcements when
232 * it is the timeline master.
233 *
234 * @return The time (in milliseconds) between master announcements.
235 * @throws android.os.RemoteException
236 */
237 public int getMasterAnnounceInterval()
238 throws RemoteException {
239 throwOnDeadServer();
240 return mUtils.transactGetInt(METHOD_GET_MASTER_ANNOUNCE_INTERVAL, -1);
241 }
242
243 /**
244 * Sets the amount of time the common time service will wait between master announcements when
245 * it is the timeline master.
246 *
247 * @param interval The time (in milliseconds) between master announcements.
248 * @return {@link #SUCCESS} in case of success,
249 * {@link #ERROR}, {@link #ERROR_BAD_VALUE} or {@link #ERROR_DEAD_OBJECT} in case of failure.
250 */
251 public int setMasterAnnounceInterval(int interval) {
252 if (checkDeadServer())
253 return ERROR_DEAD_OBJECT;
254 return mUtils.transactSetInt(METHOD_SET_MASTER_ANNOUNCE_INTERVAL, interval);
255 }
256
257 /**
258 * Gets the amount of time the common time service will wait between time synchronization
259 * requests when it is the client of another common time service on the network.
260 *
261 * @return The time (in milliseconds) between time sync requests.
262 * @throws android.os.RemoteException
263 */
264 public int getClientSyncInterval()
265 throws RemoteException {
266 throwOnDeadServer();
267 return mUtils.transactGetInt(METHOD_GET_CLIENT_SYNC_INTERVAL, -1);
268 }
269
270 /**
271 * Sets the amount of time the common time service will wait between time synchronization
272 * requests when it is the client of another common time service on the network.
273 *
274 * @param interval The time (in milliseconds) between time sync requests.
275 * @return {@link #SUCCESS} in case of success,
276 * {@link #ERROR}, {@link #ERROR_BAD_VALUE} or {@link #ERROR_DEAD_OBJECT} in case of failure.
277 */
278 public int setClientSyncInterval(int interval) {
279 if (checkDeadServer())
280 return ERROR_DEAD_OBJECT;
281 return mUtils.transactSetInt(METHOD_SET_CLIENT_SYNC_INTERVAL, interval);
282 }
283
284 /**
285 * Gets the panic threshold for the estimated error level of the common time service. When the
286 * common time service's estimated error rises above this level, the service will panic and
287 * reset, causing a discontinuity in the currently synchronized timeline.
288 *
289 * @return The threshold (in microseconds) past which the common time service will panic.
290 * @throws android.os.RemoteException
291 */
292 public int getPanicThreshold()
293 throws RemoteException {
294 throwOnDeadServer();
295 return mUtils.transactGetInt(METHOD_GET_PANIC_THRESHOLD, -1);
296 }
297
298 /**
299 * Sets the panic threshold for the estimated error level of the common time service. When the
300 * common time service's estimated error rises above this level, the service will panic and
301 * reset, causing a discontinuity in the currently synchronized timeline.
302 *
303 * @param threshold The threshold (in microseconds) past which the common time service will
304 * panic.
305 * @return {@link #SUCCESS} in case of success,
306 * {@link #ERROR}, {@link #ERROR_BAD_VALUE} or {@link #ERROR_DEAD_OBJECT} in case of failure.
307 */
308 public int setPanicThreshold(int threshold) {
309 if (checkDeadServer())
310 return ERROR_DEAD_OBJECT;
311 return mUtils.transactSetInt(METHOD_SET_PANIC_THRESHOLD, threshold);
312 }
313
314 /**
315 * Gets the current state of the common time service's auto disable flag.
316 *
317 * @return The current state of the common time service's auto disable flag.
318 * @throws android.os.RemoteException
319 */
320 public boolean getAutoDisable()
321 throws RemoteException {
322 throwOnDeadServer();
323 return (1 == mUtils.transactGetInt(METHOD_GET_AUTO_DISABLE, 1));
324 }
325
326 /**
327 * Sets the current state of the common time service's auto disable flag. When the time
328 * service's auto disable flag is set, it will automatically cease all network activity when
329 * it has no active local clients, resuming activity the next time the service has interested
330 * local clients. When the auto disabled flag is cleared, the common time service will continue
331 * to participate the time synchronization group even when it has no active local clients.
332 *
333 * @param autoDisable The desired state of the common time service's auto disable flag.
334 * @return {@link #SUCCESS} in case of success,
335 * {@link #ERROR} or {@link #ERROR_DEAD_OBJECT} in case of failure.
336 */
337 public int setAutoDisable(boolean autoDisable) {
338 if (checkDeadServer())
339 return ERROR_DEAD_OBJECT;
340
341 return mUtils.transactSetInt(METHOD_SET_AUTO_DISABLE, autoDisable ? 1 : 0);
342 }
343
344 /**
345 * At startup, the time service enters the initial state and remains there until it is given a
346 * network interface to bind to. Common time will be unavailable to clients of the common time
347 * service until the service joins a network (even an empty network). Devices may use the
348 * {@link #forceNetworklessMasterMode()} method to force a time service in the INITIAL state
349 * with no network configuration to assume MASTER status for a brand new timeline in order to
350 * allow clients of the common time service to operate, even though the device is isolated and
351 * not on any network. When a networkless master does join a network, it will defer to any
352 * masters already on the network, or continue to maintain the timeline it made up during its
353 * networkless state if no other masters are detected. Attempting to force a client into master
354 * mode while it is actively bound to a network will fail with the status code {@link #ERROR}
355 *
356 * @return {@link #SUCCESS} in case of success,
357 * {@link #ERROR} or {@link #ERROR_DEAD_OBJECT} in case of failure.
358 */
359 public int forceNetworklessMasterMode() {
360 android.os.Parcel data = android.os.Parcel.obtain();
361 android.os.Parcel reply = android.os.Parcel.obtain();
362
363 try {
364 data.writeInterfaceToken(mInterfaceDesc);
365 mRemote.transact(METHOD_FORCE_NETWORKLESS_MASTER_MODE, data, reply, 0);
366
367 return reply.readInt();
368 }
369 catch (RemoteException e) {
370 return ERROR_DEAD_OBJECT;
371 }
372 finally {
373 reply.recycle();
374 data.recycle();
375 }
376 }
377
378 /**
379 * The OnServerDiedListener interface defines a method called by the
380 * {@link android.os.CommonTimeConfig} instance to indicate that the connection to the native
381 * media server has been broken and that the {@link android.os.CommonTimeConfig} instance will
382 * need to be released and re-created. The client application can implement this interface and
383 * register the listener with the {@link #setServerDiedListener(OnServerDiedListener)} method.
384 */
385 public interface OnServerDiedListener {
386 /**
387 * Method called when the native common time service has died. <p>If the native common time
388 * service encounters a fatal error and needs to restart, the binder connection from the
389 * {@link android.os.CommonTimeConfig} instance to the common time service will be broken.
390 */
391 void onServerDied();
392 }
393
394 /**
395 * Registers an OnServerDiedListener interface.
396 * <p>Call this method with a null listener to stop receiving server death notifications.
397 */
398 public void setServerDiedListener(OnServerDiedListener listener) {
399 synchronized (mListenerLock) {
400 mServerDiedListener = listener;
401 }
402 }
403
404 protected void finalize() throws Throwable { release(); }
405
406 private boolean checkDeadServer() {
407 return ((null == mRemote) || (null == mUtils));
408 }
409
410 private void throwOnDeadServer() throws RemoteException {
411 if (checkDeadServer())
412 throw new RemoteException();
413 }
414
415 private final Object mListenerLock = new Object();
416 private OnServerDiedListener mServerDiedListener = null;
417
418 private IBinder mRemote = null;
419 private String mInterfaceDesc = "";
420 private CommonTimeUtils mUtils;
421
422 private IBinder.DeathRecipient mDeathHandler = new IBinder.DeathRecipient() {
423 public void binderDied() {
424 synchronized (mListenerLock) {
425 if (null != mServerDiedListener)
426 mServerDiedListener.onServerDied();
427 }
428 }
429 };
430
431 private static final int METHOD_GET_MASTER_ELECTION_PRIORITY = IBinder.FIRST_CALL_TRANSACTION;
432 private static final int METHOD_SET_MASTER_ELECTION_PRIORITY = METHOD_GET_MASTER_ELECTION_PRIORITY + 1;
433 private static final int METHOD_GET_MASTER_ELECTION_ENDPOINT = METHOD_SET_MASTER_ELECTION_PRIORITY + 1;
434 private static final int METHOD_SET_MASTER_ELECTION_ENDPOINT = METHOD_GET_MASTER_ELECTION_ENDPOINT + 1;
435 private static final int METHOD_GET_MASTER_ELECTION_GROUP_ID = METHOD_SET_MASTER_ELECTION_ENDPOINT + 1;
436 private static final int METHOD_SET_MASTER_ELECTION_GROUP_ID = METHOD_GET_MASTER_ELECTION_GROUP_ID + 1;
437 private static final int METHOD_GET_INTERFACE_BINDING = METHOD_SET_MASTER_ELECTION_GROUP_ID + 1;
438 private static final int METHOD_SET_INTERFACE_BINDING = METHOD_GET_INTERFACE_BINDING + 1;
439 private static final int METHOD_GET_MASTER_ANNOUNCE_INTERVAL = METHOD_SET_INTERFACE_BINDING + 1;
440 private static final int METHOD_SET_MASTER_ANNOUNCE_INTERVAL = METHOD_GET_MASTER_ANNOUNCE_INTERVAL + 1;
441 private static final int METHOD_GET_CLIENT_SYNC_INTERVAL = METHOD_SET_MASTER_ANNOUNCE_INTERVAL + 1;
442 private static final int METHOD_SET_CLIENT_SYNC_INTERVAL = METHOD_GET_CLIENT_SYNC_INTERVAL + 1;
443 private static final int METHOD_GET_PANIC_THRESHOLD = METHOD_SET_CLIENT_SYNC_INTERVAL + 1;
444 private static final int METHOD_SET_PANIC_THRESHOLD = METHOD_GET_PANIC_THRESHOLD + 1;
445 private static final int METHOD_GET_AUTO_DISABLE = METHOD_SET_PANIC_THRESHOLD + 1;
446 private static final int METHOD_SET_AUTO_DISABLE = METHOD_GET_AUTO_DISABLE + 1;
447 private static final int METHOD_FORCE_NETWORKLESS_MASTER_MODE = METHOD_SET_AUTO_DISABLE + 1;
448}