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