diff options
| author | 2010-06-15 12:19:37 -0700 | |
|---|---|---|
| committer | 2010-06-16 11:04:37 -0700 | |
| commit | 14f2ef4c9da27a3d58d65dc9f684c5f764ee279a (patch) | |
| tree | bef6430bbf98a5734add49dead51039c2489917c | |
| parent | ce718947db0d305a8cf015c29e68907d42e1b6cd (diff) | |
Move the net transition wakelock to ConnService.
When the default network goes down we lose the wake-on-incoming-data capability
until the new net is brought up and apps rebuild their connections. We fixed this
in Wifi, but it's a general connectivity issue, not a wifi issue so moving the
mechanism to connecitivty so other networks can use it.
bug:2734419
Change-Id: I39b5d825eb6b548bd9bb8f179b89254f4db53147
| -rw-r--r-- | core/java/android/net/ConnectivityManager.java | 17 | ||||
| -rw-r--r-- | core/java/android/net/IConnectivityManager.aidl | 2 | ||||
| -rw-r--r-- | core/java/android/net/NetworkStateTracker.java | 7 | ||||
| -rw-r--r-- | core/res/AndroidManifest.xml | 7 | ||||
| -rw-r--r-- | core/res/res/values/config.xml | 3 | ||||
| -rw-r--r-- | services/java/com/android/server/ConnectivityService.java | 73 | ||||
| -rw-r--r-- | services/java/com/android/server/WifiService.java | 41 | ||||
| -rw-r--r-- | wifi/java/android/net/wifi/WifiStateTracker.java | 15 |
8 files changed, 107 insertions, 58 deletions
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index 280ded6bcc94..63352968322f 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -524,5 +524,20 @@ public class ConnectivityManager } catch (RemoteException e) { return TETHER_ERROR_SERVICE_UNAVAIL; } - } + } + + /** + * Ensure the device stays awake until we connect with the next network + * @param forWhome The name of the network going down for logging purposes + * @return {@code true} on success, {@code false} on failure + * {@hide} + */ + public boolean requestNetworkTransitionWakelock(String forWhom) { + try { + mService.requestNetworkTransitionWakelock(forWhom); + return true; + } catch (RemoteException e) { + return false; + } + } } diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl index b05c2edd103b..5a14cc9a090b 100644 --- a/core/java/android/net/IConnectivityManager.aidl +++ b/core/java/android/net/IConnectivityManager.aidl @@ -72,4 +72,6 @@ interface IConnectivityManager String[] getTetherableUsbRegexs(); String[] getTetherableWifiRegexs(); + + void requestNetworkTransitionWakelock(in String forWhom); } diff --git a/core/java/android/net/NetworkStateTracker.java b/core/java/android/net/NetworkStateTracker.java index d5bcfcd3d199..cd8e7f1464dd 100644 --- a/core/java/android/net/NetworkStateTracker.java +++ b/core/java/android/net/NetworkStateTracker.java @@ -38,6 +38,7 @@ public interface NetworkStateTracker { public static final int EVENT_ROAMING_CHANGED = 5; public static final int EVENT_NETWORK_SUBTYPE_CHANGED = 6; public static final int EVENT_RESTORE_DEFAULT_NETWORK = 7; + public static final int EVENT_CLEAR_NET_TRANSITION_WAKELOCK = 8; /** * Fetch NetworkInfo for the network @@ -95,12 +96,6 @@ public interface NetworkStateTracker { */ public boolean isTeardownRequested(); - /** - * Release the wakelock, if any, that may be held while handling a - * disconnect operation. - */ - public void releaseWakeLock(); - public void startMonitoring(); /** diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index a9dbaedf20d5..5cdfc1d7758e 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -344,6 +344,13 @@ android:description="@string/permdesc_accountManagerService" android:label="@string/permlab_accountManagerService" /> + <!-- Allows an internal user to use privaledged ConnectivityManager + APIs. + @hide --> + <permission android:name="android.permission.CONNECTIVITY_INTERNAL" + android:permissionGroup="android.permission-group.NETWORK" + android:protectionLevel="signatureOrSystem" /> + <!-- ================================== --> <!-- Permissions for accessing accounts --> <!-- ================================== --> diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index cffcd1d1a1e7..ec0d83c03189 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -98,6 +98,9 @@ <item>"0,1"</item> </string-array> + <!-- The maximum duration (in milliseconds) we expect a network transition to take --> + <integer name="config_networkTransitionTimeout">60000</integer> + <!-- List of regexpressions describing the interface (if any) that represent tetherable USB interfaces. If the device doesn't want to support tething over USB this should be empty. An example would be "usb.*" --> diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 33df76c3504b..9ff7de615278 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -34,6 +34,7 @@ import android.os.Handler; import android.os.IBinder; import android.os.Looper; import android.os.Message; +import android.os.PowerManager; import android.os.RemoteException; import android.os.ServiceManager; import android.os.SystemProperties; @@ -67,7 +68,6 @@ public class ConnectivityService extends IConnectivityManager.Stub { private static final String NETWORK_RESTORE_DELAY_PROP_NAME = "android.telephony.apn-restore"; - private Tethering mTethering; private boolean mTetheringConfigValid = false; @@ -107,6 +107,11 @@ public class ConnectivityService extends IConnectivityManager.Stub { private boolean mSystemReady; private Intent mInitialBroadcast; + private PowerManager.WakeLock mNetTransitionWakeLock; + private String mNetTransitionWakeLockCausedBy = ""; + private int mNetTransitionWakeLockSerialNumber; + private int mNetTransitionWakeLockTimeout; + private static class NetworkAttributes { /** * Class for holding settings read from resources. @@ -197,6 +202,12 @@ public class ConnectivityService extends IConnectivityManager.Stub { } mContext = context; + + PowerManager powerManager = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE); + mNetTransitionWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG); + mNetTransitionWakeLockTimeout = mContext.getResources().getInteger( + com.android.internal.R.integer.config_networkTransitionTimeout); + mNetTrackers = new NetworkStateTracker[ ConnectivityManager.MAX_NETWORK_TYPE+1]; mHandler = new MyHandler(); @@ -878,6 +889,12 @@ public class ConnectivityService extends IConnectivityManager.Stub { "ConnectivityService"); } + private void enforceConnectivityInternalPermission() { + mContext.enforceCallingOrSelfPermission( + android.Manifest.permission.CONNECTIVITY_INTERNAL, + "ConnectivityService"); + } + /** * Handle a {@code DISCONNECTED} event. If this pertains to the non-active * network, we ignore it. If it is for the active network, we send out a @@ -1153,9 +1170,17 @@ public class ConnectivityService extends IConnectivityManager.Stub { Slog.e(TAG, "Network declined teardown request"); return; } - if (isFailover) { - otherNet.releaseWakeLock(); - } + } + } + synchronized (ConnectivityService.this) { + // have a new default network, release the transition wakelock in a second + // if it's held. The second pause is to allow apps to reconnect over the + // new network + if (mNetTransitionWakeLock.isHeld()) { + mHandler.sendMessageDelayed(mHandler.obtainMessage( + NetworkStateTracker.EVENT_CLEAR_NET_TRANSITION_WAKELOCK, + mNetTransitionWakeLockSerialNumber, 0), + 1000); } } mActiveDefaultNetwork = type; @@ -1546,6 +1571,13 @@ public class ConnectivityService extends IConnectivityManager.Stub { } pw.println(); + synchronized (this) { + pw.println("NetworkTranstionWakeLock is currently " + + (mNetTransitionWakeLock.isHeld() ? "" : "not ") + "held."); + pw.println("It was last requested for "+mNetTransitionWakeLockCausedBy); + } + pw.println(); + mTethering.dump(fd, pw, args); } @@ -1637,6 +1669,20 @@ public class ConnectivityService extends IConnectivityManager.Stub { FeatureUser u = (FeatureUser)msg.obj; u.expire(); break; + case NetworkStateTracker.EVENT_CLEAR_NET_TRANSITION_WAKELOCK: + String causedBy = null; + synchronized (ConnectivityService.this) { + if (msg.arg1 == mNetTransitionWakeLockSerialNumber && + mNetTransitionWakeLock.isHeld()) { + mNetTransitionWakeLock.release(); + causedBy = mNetTransitionWakeLockCausedBy; + } + } + if (causedBy != null) { + Slog.d(TAG, "NetTransition Wakelock for " + + causedBy + " released by timeout"); + } + break; } } } @@ -1720,4 +1766,23 @@ public class ConnectivityService extends IConnectivityManager.Stub { Settings.Secure.TETHER_SUPPORTED, defaultVal) != 0); return tetherEnabledInSettings && mTetheringConfigValid; } + + // An API NetworkStateTrackers can call when they lose their network. + // This will automatically be cleared after X seconds or a network becomes CONNECTED, + // whichever happens first. The timer is started by the first caller and not + // restarted by subsequent callers. + public void requestNetworkTransitionWakelock(String forWhom) { + enforceConnectivityInternalPermission(); + synchronized (this) { + if (mNetTransitionWakeLock.isHeld()) return; + mNetTransitionWakeLockSerialNumber++; + mNetTransitionWakeLock.acquire(); + mNetTransitionWakeLockCausedBy = forWhom; + } + mHandler.sendMessageDelayed(mHandler.obtainMessage( + NetworkStateTracker.EVENT_CLEAR_NET_TRANSITION_WAKELOCK, + mNetTransitionWakeLockSerialNumber, 0), + mNetTransitionWakeLockTimeout); + return; + } } diff --git a/services/java/com/android/server/WifiService.java b/services/java/com/android/server/WifiService.java index 46a68ac3f03b..6d9888b24526 100644 --- a/services/java/com/android/server/WifiService.java +++ b/services/java/com/android/server/WifiService.java @@ -144,19 +144,6 @@ public class WifiService extends IWifiManager.Stub { private static final String WAKELOCK_TAG = "WifiService"; - /** - * The maximum amount of time to hold the wake lock after a disconnect - * caused by stopping the driver. Establishing an EDGE connection has been - * observed to take about 5 seconds under normal circumstances. This - * provides a bit of extra margin. - * <p> - * See {@link android.provider.Settings.Secure#WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS}. - * This is the default value if a Settings.Secure value is not present. - */ - private static final int DEFAULT_WAKELOCK_TIMEOUT = 8000; - - // Wake lock used by driver-stop operation - private static PowerManager.WakeLock sDriverStopWakeLock; // Wake lock used by other operations private static PowerManager.WakeLock sWakeLock; @@ -164,7 +151,6 @@ public class WifiService extends IWifiManager.Stub { private static final int MESSAGE_DISABLE_WIFI = 1; private static final int MESSAGE_STOP_WIFI = 2; private static final int MESSAGE_START_WIFI = 3; - private static final int MESSAGE_RELEASE_WAKELOCK = 4; private static final int MESSAGE_UPDATE_STATE = 5; private static final int MESSAGE_START_ACCESS_POINT = 6; private static final int MESSAGE_STOP_ACCESS_POINT = 7; @@ -238,7 +224,6 @@ public class WifiService extends IWifiManager.Stub { PowerManager powerManager = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE); sWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_TAG); - sDriverStopWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_TAG); mContext.registerReceiver( new BroadcastReceiver() { @@ -293,7 +278,10 @@ public class WifiService extends IWifiManager.Stub { IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE); INetworkManagementService service = INetworkManagementService.Stub.asInterface(b); - mCm = (ConnectivityManager)mContext.getSystemService(Context.CONNECTIVITY_SERVICE); + if (mCm == null) { + mCm = (ConnectivityManager)mContext.getSystemService(Context.CONNECTIVITY_SERVICE); + } + mWifiRegexs = mCm.getTetherableWifiRegexs(); for (String intf : available) { @@ -1827,19 +1815,12 @@ public class WifiService extends IWifiManager.Stub { sWakeLock.acquire(); sendStartMessage(strongestLockMode == WifiManager.WIFI_MODE_SCAN_ONLY); } else if (!mWifiStateTracker.isDriverStopped()) { - int wakeLockTimeout = - Settings.Secure.getInt( - mContext.getContentResolver(), - Settings.Secure.WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS, - DEFAULT_WAKELOCK_TIMEOUT); - /* - * We are assuming that ConnectivityService can make - * a transition to cellular data within wakeLockTimeout time. - * The wakelock is released by the delayed message. - */ - sDriverStopWakeLock.acquire(); + if (mCm == null) { + mCm = (ConnectivityManager)mContext. + getSystemService(Context.CONNECTIVITY_SERVICE); + } + mCm.requestNetworkTransitionWakelock(TAG); mWifiHandler.sendEmptyMessage(MESSAGE_STOP_WIFI); - mWifiHandler.sendEmptyMessageDelayed(MESSAGE_RELEASE_WAKELOCK, wakeLockTimeout); } } else { sWakeLock.acquire(); @@ -1925,10 +1906,6 @@ public class WifiService extends IWifiManager.Stub { // don't release wakelock break; - case MESSAGE_RELEASE_WAKELOCK: - sDriverStopWakeLock.release(); - break; - case MESSAGE_START_ACCESS_POINT: setWifiApEnabledBlocking(true, msg.arg1, diff --git a/wifi/java/android/net/wifi/WifiStateTracker.java b/wifi/java/android/net/wifi/WifiStateTracker.java index 73cba9383dae..2bd5640e6052 100644 --- a/wifi/java/android/net/wifi/WifiStateTracker.java +++ b/wifi/java/android/net/wifi/WifiStateTracker.java @@ -764,21 +764,6 @@ public class WifiStateTracker extends Handler implements NetworkStateTracker { } /** - * We release the wakelock in WifiService - * using a timer. - * - * TODO: - * Releasing wakelock using both timer and - * a call from ConnectivityService requires - * a rethink. We had problems where WifiService - * could keep a wakelock forever if we delete - * messages in the asynchronous call - * from ConnectivityService - */ - public void releaseWakeLock() { - } - - /** * Tracks the WPA supplicant states to detect "loop" situations. * @param newSupplicantState The new WPA supplicant state. * @return {@code true} if the supplicant loop should be stopped |