Home | History | Annotate | Download | only in os
      1 /*
      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  */
     16 package android.os;
     17 
     18 import java.net.InetAddress;
     19 import java.net.InetSocketAddress;
     20 import java.util.NoSuchElementException;
     21 
     22 import android.os.CommonTimeUtils;
     23 import android.os.IBinder;
     24 import android.os.RemoteException;
     25 import android.os.ServiceManager;
     26 
     27 /**
     28  * Used for configuring and controlling the status of the android common time service.
     29  * @hide
     30  */
     31 public 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 }
    449