/services/java/com/android/server/CommonTimeManagementService.java

https://github.com/aizuzi/platform_frameworks_base · Java · 376 lines · 264 code · 40 blank · 72 comment · 54 complexity · 7607c5e672f9c7524a34154c0a6f42a3 MD5 · raw file

  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 com.android.server;
  17. import java.io.FileDescriptor;
  18. import java.io.PrintWriter;
  19. import java.net.InetAddress;
  20. import android.content.BroadcastReceiver;
  21. import android.content.Context;
  22. import android.content.Intent;
  23. import android.content.IntentFilter;
  24. import android.content.pm.PackageManager;
  25. import android.net.ConnectivityManager;
  26. import android.net.IConnectivityManager;
  27. import android.net.INetworkManagementEventObserver;
  28. import android.net.InterfaceConfiguration;
  29. import android.net.NetworkInfo;
  30. import android.os.Binder;
  31. import android.os.CommonTimeConfig;
  32. import android.os.Handler;
  33. import android.os.IBinder;
  34. import android.os.INetworkManagementService;
  35. import android.os.RemoteException;
  36. import android.os.ServiceManager;
  37. import android.os.SystemProperties;
  38. import android.util.Log;
  39. import com.android.server.net.BaseNetworkObserver;
  40. /**
  41. * @hide
  42. * <p>CommonTimeManagementService manages the configuration of the native Common Time service,
  43. * reconfiguring the native service as appropriate in response to changes in network configuration.
  44. */
  45. class CommonTimeManagementService extends Binder {
  46. /*
  47. * Constants and globals.
  48. */
  49. private static final String TAG = CommonTimeManagementService.class.getSimpleName();
  50. private static final int NATIVE_SERVICE_RECONNECT_TIMEOUT = 5000;
  51. private static final String AUTO_DISABLE_PROP = "ro.common_time.auto_disable";
  52. private static final String ALLOW_WIFI_PROP = "ro.common_time.allow_wifi";
  53. private static final String SERVER_PRIO_PROP = "ro.common_time.server_prio";
  54. private static final String NO_INTERFACE_TIMEOUT_PROP = "ro.common_time.no_iface_timeout";
  55. private static final boolean AUTO_DISABLE;
  56. private static final boolean ALLOW_WIFI;
  57. private static final byte BASE_SERVER_PRIO;
  58. private static final int NO_INTERFACE_TIMEOUT;
  59. private static final InterfaceScoreRule[] IFACE_SCORE_RULES;
  60. static {
  61. int tmp;
  62. AUTO_DISABLE = (0 != SystemProperties.getInt(AUTO_DISABLE_PROP, 1));
  63. ALLOW_WIFI = (0 != SystemProperties.getInt(ALLOW_WIFI_PROP, 0));
  64. tmp = SystemProperties.getInt(SERVER_PRIO_PROP, 1);
  65. NO_INTERFACE_TIMEOUT = SystemProperties.getInt(NO_INTERFACE_TIMEOUT_PROP, 60000);
  66. if (tmp < 1)
  67. BASE_SERVER_PRIO = 1;
  68. else
  69. if (tmp > 30)
  70. BASE_SERVER_PRIO = 30;
  71. else
  72. BASE_SERVER_PRIO = (byte)tmp;
  73. if (ALLOW_WIFI) {
  74. IFACE_SCORE_RULES = new InterfaceScoreRule[] {
  75. new InterfaceScoreRule("wlan", (byte)1),
  76. new InterfaceScoreRule("eth", (byte)2),
  77. };
  78. } else {
  79. IFACE_SCORE_RULES = new InterfaceScoreRule[] {
  80. new InterfaceScoreRule("eth", (byte)2),
  81. };
  82. }
  83. };
  84. /*
  85. * Internal state
  86. */
  87. private final Context mContext;
  88. private INetworkManagementService mNetMgr;
  89. private CommonTimeConfig mCTConfig;
  90. private String mCurIface;
  91. private Handler mReconnectHandler = new Handler();
  92. private Handler mNoInterfaceHandler = new Handler();
  93. private Object mLock = new Object();
  94. private boolean mDetectedAtStartup = false;
  95. private byte mEffectivePrio = BASE_SERVER_PRIO;
  96. /*
  97. * Callback handler implementations.
  98. */
  99. private INetworkManagementEventObserver mIfaceObserver = new BaseNetworkObserver() {
  100. public void interfaceStatusChanged(String iface, boolean up) {
  101. reevaluateServiceState();
  102. }
  103. public void interfaceLinkStateChanged(String iface, boolean up) {
  104. reevaluateServiceState();
  105. }
  106. public void interfaceAdded(String iface) {
  107. reevaluateServiceState();
  108. }
  109. public void interfaceRemoved(String iface) {
  110. reevaluateServiceState();
  111. }
  112. };
  113. private BroadcastReceiver mConnectivityMangerObserver = new BroadcastReceiver() {
  114. @Override
  115. public void onReceive(Context context, Intent intent) {
  116. reevaluateServiceState();
  117. }
  118. };
  119. private CommonTimeConfig.OnServerDiedListener mCTServerDiedListener =
  120. new CommonTimeConfig.OnServerDiedListener() {
  121. public void onServerDied() {
  122. scheduleTimeConfigReconnect();
  123. }
  124. };
  125. private Runnable mReconnectRunnable = new Runnable() {
  126. public void run() { connectToTimeConfig(); }
  127. };
  128. private Runnable mNoInterfaceRunnable = new Runnable() {
  129. public void run() { handleNoInterfaceTimeout(); }
  130. };
  131. /*
  132. * Public interface (constructor, systemReady and dump)
  133. */
  134. public CommonTimeManagementService(Context context) {
  135. mContext = context;
  136. }
  137. void systemRunning() {
  138. if (ServiceManager.checkService(CommonTimeConfig.SERVICE_NAME) == null) {
  139. Log.i(TAG, "No common time service detected on this platform. " +
  140. "Common time services will be unavailable.");
  141. return;
  142. }
  143. mDetectedAtStartup = true;
  144. IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
  145. mNetMgr = INetworkManagementService.Stub.asInterface(b);
  146. // Network manager is running along-side us, so we should never receiver a remote exception
  147. // while trying to register this observer.
  148. try {
  149. mNetMgr.registerObserver(mIfaceObserver);
  150. }
  151. catch (RemoteException e) { }
  152. // Register with the connectivity manager for connectivity changed intents.
  153. IntentFilter filter = new IntentFilter();
  154. filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
  155. mContext.registerReceiver(mConnectivityMangerObserver, filter);
  156. // Connect to the common time config service and apply the initial configuration.
  157. connectToTimeConfig();
  158. }
  159. @Override
  160. protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
  161. if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
  162. != PackageManager.PERMISSION_GRANTED) {
  163. pw.println(String.format(
  164. "Permission Denial: can't dump CommonTimeManagement service from from " +
  165. "pid=%d, uid=%d", Binder.getCallingPid(), Binder.getCallingUid()));
  166. return;
  167. }
  168. if (!mDetectedAtStartup) {
  169. pw.println("Native Common Time service was not detected at startup. " +
  170. "Service is unavailable");
  171. return;
  172. }
  173. synchronized (mLock) {
  174. pw.println("Current Common Time Management Service Config:");
  175. pw.println(String.format(" Native service : %s",
  176. (null == mCTConfig) ? "reconnecting"
  177. : "alive"));
  178. pw.println(String.format(" Bound interface : %s",
  179. (null == mCurIface ? "unbound" : mCurIface)));
  180. pw.println(String.format(" Allow WiFi : %s", ALLOW_WIFI ? "yes" : "no"));
  181. pw.println(String.format(" Allow Auto Disable : %s", AUTO_DISABLE ? "yes" : "no"));
  182. pw.println(String.format(" Server Priority : %d", mEffectivePrio));
  183. pw.println(String.format(" No iface timeout : %d", NO_INTERFACE_TIMEOUT));
  184. }
  185. }
  186. /*
  187. * Inner helper classes
  188. */
  189. private static class InterfaceScoreRule {
  190. public final String mPrefix;
  191. public final byte mScore;
  192. public InterfaceScoreRule(String prefix, byte score) {
  193. mPrefix = prefix;
  194. mScore = score;
  195. }
  196. };
  197. /*
  198. * Internal implementation
  199. */
  200. private void cleanupTimeConfig() {
  201. mReconnectHandler.removeCallbacks(mReconnectRunnable);
  202. mNoInterfaceHandler.removeCallbacks(mNoInterfaceRunnable);
  203. if (null != mCTConfig) {
  204. mCTConfig.release();
  205. mCTConfig = null;
  206. }
  207. }
  208. private void connectToTimeConfig() {
  209. // Get access to the common time service configuration interface. If we catch a remote
  210. // exception in the process (service crashed or no running for w/e reason), schedule an
  211. // attempt to reconnect in the future.
  212. cleanupTimeConfig();
  213. try {
  214. synchronized (mLock) {
  215. mCTConfig = new CommonTimeConfig();
  216. mCTConfig.setServerDiedListener(mCTServerDiedListener);
  217. mCurIface = mCTConfig.getInterfaceBinding();
  218. mCTConfig.setAutoDisable(AUTO_DISABLE);
  219. mCTConfig.setMasterElectionPriority(mEffectivePrio);
  220. }
  221. if (NO_INTERFACE_TIMEOUT >= 0)
  222. mNoInterfaceHandler.postDelayed(mNoInterfaceRunnable, NO_INTERFACE_TIMEOUT);
  223. reevaluateServiceState();
  224. }
  225. catch (RemoteException e) {
  226. scheduleTimeConfigReconnect();
  227. }
  228. }
  229. private void scheduleTimeConfigReconnect() {
  230. cleanupTimeConfig();
  231. Log.w(TAG, String.format("Native service died, will reconnect in %d mSec",
  232. NATIVE_SERVICE_RECONNECT_TIMEOUT));
  233. mReconnectHandler.postDelayed(mReconnectRunnable,
  234. NATIVE_SERVICE_RECONNECT_TIMEOUT);
  235. }
  236. private void handleNoInterfaceTimeout() {
  237. if (null != mCTConfig) {
  238. Log.i(TAG, "Timeout waiting for interface to come up. " +
  239. "Forcing networkless master mode.");
  240. if (CommonTimeConfig.ERROR_DEAD_OBJECT == mCTConfig.forceNetworklessMasterMode())
  241. scheduleTimeConfigReconnect();
  242. }
  243. }
  244. private void reevaluateServiceState() {
  245. String bindIface = null;
  246. byte bestScore = -1;
  247. try {
  248. // Check to see if this interface is suitable to use for time synchronization.
  249. //
  250. // TODO : This selection algorithm needs to be enhanced for use with mobile devices. In
  251. // particular, the choice of whether to a wireless interface or not should not be an all
  252. // or nothing thing controlled by properties. It would probably be better if the
  253. // platform had some concept of public wireless networks vs. home or friendly wireless
  254. // networks (something a user would configure in settings or when a new interface is
  255. // added). Then this algorithm could pick only wireless interfaces which were flagged
  256. // as friendly, and be dormant when on public wireless networks.
  257. //
  258. // Another issue which needs to be dealt with is the use of driver supplied interface
  259. // name to determine the network type. The fact that the wireless interface on a device
  260. // is named "wlan0" is just a matter of convention; its not a 100% rule. For example,
  261. // there are devices out there where the wireless is name "tiwlan0", not "wlan0". The
  262. // internal network management interfaces in Android have all of the information needed
  263. // to make a proper classification, there is just no way (currently) to fetch an
  264. // interface's type (available from the ConnectionManager) as well as its address
  265. // (available from either the java.net interfaces or from the NetworkManagment service).
  266. // Both can enumerate interfaces, but that is no way to correlate their results (no
  267. // common shared key; although using the interface name in the connection manager would
  268. // be a good start). Until this gets resolved, we resort to substring searching for
  269. // tags like wlan and eth.
  270. //
  271. String ifaceList[] = mNetMgr.listInterfaces();
  272. if (null != ifaceList) {
  273. for (String iface : ifaceList) {
  274. byte thisScore = -1;
  275. for (InterfaceScoreRule r : IFACE_SCORE_RULES) {
  276. if (iface.contains(r.mPrefix)) {
  277. thisScore = r.mScore;
  278. break;
  279. }
  280. }
  281. if (thisScore <= bestScore)
  282. continue;
  283. InterfaceConfiguration config = mNetMgr.getInterfaceConfig(iface);
  284. if (null == config)
  285. continue;
  286. if (config.isActive()) {
  287. bindIface = iface;
  288. bestScore = thisScore;
  289. }
  290. }
  291. }
  292. }
  293. catch (RemoteException e) {
  294. // Bad news; we should not be getting remote exceptions from the connectivity manager
  295. // since it is running in SystemServer along side of us. It probably does not matter
  296. // what we do here, but go ahead and unbind the common time service in this case, just
  297. // so we have some defined behavior.
  298. bindIface = null;
  299. }
  300. boolean doRebind = true;
  301. synchronized (mLock) {
  302. if ((null != bindIface) && (null == mCurIface)) {
  303. Log.e(TAG, String.format("Binding common time service to %s.", bindIface));
  304. mCurIface = bindIface;
  305. } else
  306. if ((null == bindIface) && (null != mCurIface)) {
  307. Log.e(TAG, "Unbinding common time service.");
  308. mCurIface = null;
  309. } else
  310. if ((null != bindIface) && (null != mCurIface) && !bindIface.equals(mCurIface)) {
  311. Log.e(TAG, String.format("Switching common time service binding from %s to %s.",
  312. mCurIface, bindIface));
  313. mCurIface = bindIface;
  314. } else {
  315. doRebind = false;
  316. }
  317. }
  318. if (doRebind && (null != mCTConfig)) {
  319. byte newPrio = (bestScore > 0)
  320. ? (byte)(bestScore * BASE_SERVER_PRIO)
  321. : BASE_SERVER_PRIO;
  322. if (newPrio != mEffectivePrio) {
  323. mEffectivePrio = newPrio;
  324. mCTConfig.setMasterElectionPriority(mEffectivePrio);
  325. }
  326. int res = mCTConfig.setNetworkBinding(mCurIface);
  327. if (res != CommonTimeConfig.SUCCESS)
  328. scheduleTimeConfigReconnect();
  329. else if (NO_INTERFACE_TIMEOUT >= 0) {
  330. mNoInterfaceHandler.removeCallbacks(mNoInterfaceRunnable);
  331. if (null == mCurIface)
  332. mNoInterfaceHandler.postDelayed(mNoInterfaceRunnable, NO_INTERFACE_TIMEOUT);
  333. }
  334. }
  335. }
  336. }