diff --git a/api/current.xml b/api/current.xml index ce1b7269428bc..bf3044e30fce3 100644 --- a/api/current.xml +++ b/api/current.xml @@ -309,6 +309,17 @@ visibility="public" > + + + + + + + + + + + + + + + + + + + allow Wi-Fi Multicast + reception + + Allows an application to + receive packets not directly addressed to your device. This can be + useful when discovering services offered near by. It uses more power + than the non-multicast mode. + bluetooth administration diff --git a/services/java/com/android/server/WifiService.java b/services/java/com/android/server/WifiService.java index 5fa8701fda050..1528ba34efc72 100644 --- a/services/java/com/android/server/WifiService.java +++ b/services/java/com/android/server/WifiService.java @@ -588,6 +588,12 @@ public class WifiService extends IWifiManager.Stub { } + private void enforceMulticastChangePermission() { + mContext.enforceCallingOrSelfPermission( + android.Manifest.permission.CHANGE_WIFI_MULTICAST_STATE, + "WifiService"); + } + /** * see {@link WifiManager#getWifiState()} * @return One of {@link WifiManager#WIFI_STATE_DISABLED}, @@ -1930,8 +1936,8 @@ public class WifiService extends IWifiManager.Stub { } } - public void enableMulticast(IBinder binder, String tag) { - enforceChangePermission(); + public void acquireMulticastLock(IBinder binder, String tag) { + enforceMulticastChangePermission(); synchronized (mMulticasters) { mMulticastEnabled++; @@ -1953,8 +1959,8 @@ public class WifiService extends IWifiManager.Stub { } } - public void disableMulticast() { - enforceChangePermission(); + public void releaseMulticastLock() { + enforceMulticastChangePermission(); int uid = Binder.getCallingUid(); synchronized (mMulticasters) { diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl index 7c3af69341e5b..3d65d3c66f388 100644 --- a/wifi/java/android/net/wifi/IWifiManager.aidl +++ b/wifi/java/android/net/wifi/IWifiManager.aidl @@ -72,8 +72,8 @@ interface IWifiManager boolean isMulticastEnabled(); - void enableMulticast(IBinder binder, String tag); + void acquireMulticastLock(IBinder binder, String tag); - void disableMulticast(); + void releaseMulticastLock(); } diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java index 1a7caef187983..5b8ced67662cf 100644 --- a/wifi/java/android/net/wifi/WifiManager.java +++ b/wifi/java/android/net/wifi/WifiManager.java @@ -824,6 +824,117 @@ public class WifiManager { return new WifiLock(WIFI_MODE_FULL, tag); } + + /** + * Create a new MulticastLock + * + * @param tag a tag for the MulticastLock to identify it in debugging + * messages. + * + * @return a new, unacquired MulticastLock with the given tag. + * + * @see MulticastLock + */ + public MulticastLock createMulticastLock(String tag) { + return new MulticastLock(tag); + } + + /** + * Allows an application to receive Wifi Multicast packets. + * Normally the Wifi stack filters out packets not explicitly + * addressed to this device. Acquring a MulticastLock will + * cause the stack to receive packets addressed to multicast + * addresses. Processing these extra packets can cause a noticable + * battery drain and should be disabled when not needed + */ + public class MulticastLock { + private String mTag; + private final IBinder mBinder; + private boolean mHeld; + + private MulticastLock(String tag) { + mTag = tag; + mBinder = new Binder(); + mHeld = false; + } + + /** + * Locks Wifi Multicast on until {@link #release} is called. + * + * The first call to {@code acquire} will lock the Multicast on + * but subsequent calls will be ignored. Only one call to + * {@link #release} will be required, regardless of the number of + * times that {@code acquire} is called. + * + * Note that other applications may also lock Wifi Multicast on. + * Only they can relinquish their lock. + * + * Also note that applications cannot leave Multicast locked on. + * When an app exits or crashes, any Multicast locks will be released. + */ + public void acquire() { + synchronized (mBinder) { + if (!mHeld) { + try { + mService.acquireMulticastLock(mBinder, mTag); + mHeld = true; + } catch (RemoteException ignore) { + } + } + } + } + + /** + * Unlocks Wifi Multicast, restoring the filter of packets + * not addressed specifically to this device and saving power. + * + * Note that if any other Wifi Multicast Locks are still outstanding + * this {@code release} call will not have an immediate effect. Only + * when all applications have released all their Multicast Locks will + * the Multicast filter be turned back on. + * + * Also note that when an app exits or crashes all of its Multicast + * Locks will be automatically released. + */ + public void release() { + synchronized (mBinder) { + if (mHeld) { + try { + mService.releaseMulticastLock(); + mHeld = false; + } catch (RemoteException ignore) { + } + } + } + } + + /** + * Checks whether this MulticastLock is currently held. + * + * @return true if this MulticastLock is held, false otherwise + */ + public boolean isHeld() { + synchronized (mBinder) { + return mHeld; + } + } + + public String toString() { + String s1, s2; + synchronized (mBinder) { + s1 = Integer.toHexString(System.identityHashCode(this)); + s2 = mHeld ? "held; " : ""; + return "MulticastLock{ " + s1 + "; " + s2 + " }"; + } + } + + @Override + protected void finalize() throws Throwable { + super.finalize(); + release(); + } + } + /** * Check multicast filter status. * @@ -838,50 +949,4 @@ public class WifiManager { return false; } } - - /** - * Turn on the reception of multicast packets. - * The default behavior is to disable multicast packets as they - * have a noticable negative effect on battery life. An - * application can turn them on, but should not leave it on for longer - * than needed. When the app quits (or crashes) its request will - * be reverted. - * - * @param tag a string associated with this request for debugging. - * - * @return true on success - * - * @see #disableMulticast - * - * @hide pending API council approval - */ - public boolean enableMulticast(String tag) { - try { - mService.enableMulticast(new Binder(), tag); - return true; - } catch (RemoteException e) { - return false; - } - } - - /** - * Return to the default multicast-off setting. - * Note that if others had turned on Multicast reception, your - * call will not turn it back off - they must also turn off their - * request for multicast reception. - * - * @return true on success - * - * @see #enableMulticast - * - * @hide pending API council approval - */ - public boolean disableMulticast() { - try { - mService.disableMulticast(); - return true; - } catch (RemoteException e) { - return false; - } - } } diff --git a/wifi/java/android/net/wifi/WifiStateTracker.java b/wifi/java/android/net/wifi/WifiStateTracker.java index 6771136ee3793..2fbc779503589 100644 --- a/wifi/java/android/net/wifi/WifiStateTracker.java +++ b/wifi/java/android/net/wifi/WifiStateTracker.java @@ -747,8 +747,10 @@ public class WifiStateTracker extends NetworkStateTracker { * first and then off.. if nobody else wants it on it'll be * off then and it's all synchronized within the API. */ - mWM.enableMulticast("WifiStateTracker"); - mWM.disableMulticast(); + WifiManager.MulticastLock l = + mWM.createMulticastLock("WifiStateTracker"); + l.acquire(); + l.release(); if (mBluetoothA2dp == null) { mBluetoothA2dp = new BluetoothA2dp(mContext);