summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRobert Greenwalt <robdroid@android.com>2009-05-13 15:10:16 -0700
committerRobert Greenwalt <robdroid@android.com>2009-05-13 15:10:16 -0700
commit5347bd4cda2b6afc18f8acab48e52131f35ed13c (patch)
treeaf3c0e520ff5712344bd5174b7d02d24ef34c4e7
parent6347c322b36cdf6a30a35e80d205d00d40368e61 (diff)
downloadframeworks_base-5347bd4cda2b6afc18f8acab48e52131f35ed13c.zip
frameworks_base-5347bd4cda2b6afc18f8acab48e52131f35ed13c.tar.gz
frameworks_base-5347bd4cda2b6afc18f8acab48e52131f35ed13c.tar.bz2
Add wifi multicast filter api (enable/disable).
Fixes 1833432. Automatically re-disables any request when the app exits/crashes. Also hooked into Battery Stats for power managment analysis.
-rw-r--r--core/java/android/os/BatteryStats.java11
-rw-r--r--core/java/com/android/internal/app/IBatteryStats.aidl2
-rw-r--r--core/java/com/android/internal/os/BatteryStatsImpl.java58
-rw-r--r--services/java/com/android/server/WifiService.java135
-rw-r--r--services/java/com/android/server/am/BatteryStatsService.java14
-rw-r--r--wifi/java/android/net/wifi/IWifiManager.aidl6
-rw-r--r--wifi/java/android/net/wifi/WifiManager.java61
-rw-r--r--wifi/java/android/net/wifi/WifiStateTracker.java14
8 files changed, 273 insertions, 28 deletions
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 333ba73..8a0fd58 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -61,6 +61,13 @@ public abstract class BatteryStats implements Parcelable {
*/
public static final int SCAN_WIFI_LOCK = 6;
+ /**
+ * A constant indicating a wifi multicast timer
+ *
+ * {@hide}
+ */
+ public static final int WIFI_MULTICAST_ENABLED = 7;
+
/**
* Include all of the data in the stats, including previously saved data.
*/
@@ -225,9 +232,13 @@ public abstract class BatteryStats implements Parcelable {
public abstract void noteFullWifiLockReleasedLocked();
public abstract void noteScanWifiLockAcquiredLocked();
public abstract void noteScanWifiLockReleasedLocked();
+ public abstract void noteWifiMulticastEnabledLocked();
+ public abstract void noteWifiMulticastDisabledLocked();
public abstract long getWifiTurnedOnTime(long batteryRealtime, int which);
public abstract long getFullWifiLockTime(long batteryRealtime, int which);
public abstract long getScanWifiLockTime(long batteryRealtime, int which);
+ public abstract long getWifiMulticastTime(long batteryRealtime,
+ int which);
/**
* Note that these must match the constants in android.os.LocalPowerManager.
diff --git a/core/java/com/android/internal/app/IBatteryStats.aidl b/core/java/com/android/internal/app/IBatteryStats.aidl
index 9ce532c..e1ff2a5 100644
--- a/core/java/com/android/internal/app/IBatteryStats.aidl
+++ b/core/java/com/android/internal/app/IBatteryStats.aidl
@@ -45,6 +45,8 @@ interface IBatteryStats {
void noteFullWifiLockReleased(int uid);
void noteScanWifiLockAcquired(int uid);
void noteScanWifiLockReleased(int uid);
+ void noteWifiMulticastEnabled(int uid);
+ void noteWifiMulticastDisabled(int uid);
void setOnBattery(boolean onBattery, int level);
void recordCurrentLevel(int level);
long getAwakeTimeBattery();
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 1218fe3..e8356a2 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -1115,7 +1115,21 @@ public final class BatteryStatsImpl extends BatteryStats {
u.noteScanWifiLockReleasedLocked();
}
}
-
+
+ public void noteWifiMulticastEnabledLocked(int uid) {
+ Uid u = mUidStats.get(uid);
+ if (u != null) {
+ u.noteWifiMulticastEnabledLocked();
+ }
+ }
+
+ public void noteWifiMulticastDisabledLocked(int uid) {
+ Uid u = mUidStats.get(uid);
+ if (u != null) {
+ u.noteWifiMulticastDisabledLocked();
+ }
+ }
+
@Override public long getScreenOnTime(long batteryRealtime, int which) {
return mScreenOnTimer.getTotalTimeLocked(batteryRealtime, which);
}
@@ -1200,7 +1214,10 @@ public final class BatteryStatsImpl extends BatteryStats {
boolean mScanWifiLockOut;
StopwatchTimer mScanWifiLockTimer;
-
+
+ boolean mWifiMulticastEnabled;
+ StopwatchTimer mWifiMulticastTimer;
+
Counter[] mUserActivityCounters;
/**
@@ -1228,6 +1245,8 @@ public final class BatteryStatsImpl extends BatteryStats {
mWifiTurnedOnTimer = new StopwatchTimer(WIFI_TURNED_ON, null, mUnpluggables);
mFullWifiLockTimer = new StopwatchTimer(FULL_WIFI_LOCK, null, mUnpluggables);
mScanWifiLockTimer = new StopwatchTimer(SCAN_WIFI_LOCK, null, mUnpluggables);
+ mWifiMulticastTimer = new StopwatchTimer(WIFI_MULTICAST_ENABLED,
+ null, mUnpluggables);
}
@Override
@@ -1334,7 +1353,23 @@ public final class BatteryStatsImpl extends BatteryStats {
mScanWifiLockTimer.stopRunningLocked(BatteryStatsImpl.this);
}
}
-
+
+ @Override
+ public void noteWifiMulticastEnabledLocked() {
+ if (!mWifiMulticastEnabled) {
+ mWifiMulticastEnabled = true;
+ mWifiMulticastTimer.startRunningLocked(BatteryStatsImpl.this);
+ }
+ }
+
+ @Override
+ public void noteWifiMulticastDisabledLocked() {
+ if (mWifiMulticastEnabled) {
+ mWifiMulticastEnabled = false;
+ mWifiMulticastTimer.stopRunningLocked(BatteryStatsImpl.this);
+ }
+ }
+
@Override
public long getWifiTurnedOnTime(long batteryRealtime, int which) {
return mWifiTurnedOnTimer.getTotalTimeLocked(batteryRealtime, which);
@@ -1349,7 +1384,13 @@ public final class BatteryStatsImpl extends BatteryStats {
public long getScanWifiLockTime(long batteryRealtime, int which) {
return mScanWifiLockTimer.getTotalTimeLocked(batteryRealtime, which);
}
-
+
+ @Override
+ public long getWifiMulticastTime(long batteryRealtime, int which) {
+ return mWifiMulticastTimer.getTotalTimeLocked(batteryRealtime,
+ which);
+ }
+
@Override
public void noteUserActivityLocked(int type) {
if (mUserActivityCounters == null) {
@@ -1423,6 +1464,7 @@ public final class BatteryStatsImpl extends BatteryStats {
mWifiTurnedOnTimer.writeToParcel(out, batteryRealtime);
mFullWifiLockTimer.writeToParcel(out, batteryRealtime);
mScanWifiLockTimer.writeToParcel(out, batteryRealtime);
+ mWifiMulticastTimer.writeToParcel(out, batteryRealtime);
if (mUserActivityCounters == null) {
out.writeInt(0);
} else {
@@ -1482,6 +1524,9 @@ public final class BatteryStatsImpl extends BatteryStats {
mFullWifiLockTimer = new StopwatchTimer(FULL_WIFI_LOCK, null, mUnpluggables, in);
mScanWifiLockOut = false;
mScanWifiLockTimer = new StopwatchTimer(SCAN_WIFI_LOCK, null, mUnpluggables, in);
+ mWifiMulticastEnabled = false;
+ mWifiMulticastTimer = new StopwatchTimer(WIFI_MULTICAST_ENABLED,
+ null, mUnpluggables, in);
if (in.readInt() == 0) {
mUserActivityCounters = null;
} else {
@@ -2709,7 +2754,9 @@ public final class BatteryStatsImpl extends BatteryStats {
u.mFullWifiLockTimer.readSummaryFromParcelLocked(in);
u.mScanWifiLockOut = false;
u.mScanWifiLockTimer.readSummaryFromParcelLocked(in);
-
+ u.mWifiMulticastEnabled = false;
+ u.mWifiMulticastTimer.readSummaryFromParcelLocked(in);
+
if (in.readInt() != 0) {
if (u.mUserActivityCounters == null) {
u.initUserActivityLocked();
@@ -2842,6 +2889,7 @@ public final class BatteryStatsImpl extends BatteryStats {
u.mWifiTurnedOnTimer.writeSummaryFromParcelLocked(out, NOWREAL);
u.mFullWifiLockTimer.writeSummaryFromParcelLocked(out, NOWREAL);
u.mScanWifiLockTimer.writeSummaryFromParcelLocked(out, NOWREAL);
+ u.mWifiMulticastTimer.writeSummaryFromParcelLocked(out, NOWREAL);
if (u.mUserActivityCounters == null) {
out.writeInt(0);
diff --git a/services/java/com/android/server/WifiService.java b/services/java/com/android/server/WifiService.java
index 8850c31..348f0a1 100644
--- a/services/java/com/android/server/WifiService.java
+++ b/services/java/com/android/server/WifiService.java
@@ -96,6 +96,11 @@ public class WifiService extends IWifiManager.Stub {
private int mScanLocksAcquired;
private int mScanLocksReleased;
+ private final List<WifiMulticaster> mMulticasters =
+ new ArrayList<WifiMulticaster>();
+ private int mMulticastEnabled;
+ private int mMulticastDisabled;
+
private final IBatteryStats mBatteryStats;
/**
@@ -1727,21 +1732,9 @@ public class WifiService extends IWifiManager.Stub {
}
}
- private class WifiLock implements IBinder.DeathRecipient {
- String mTag;
- int mLockMode;
- IBinder mBinder;
-
+ private class WifiLock extends WifiDeathRecipient {
WifiLock(int lockMode, String tag, IBinder binder) {
- super();
- mTag = tag;
- mLockMode = lockMode;
- mBinder = binder;
- try {
- mBinder.linkToDeath(this, 0);
- } catch (RemoteException e) {
- binderDied();
- }
+ super(lockMode, tag, binder);
}
public void binderDied() {
@@ -1751,7 +1744,7 @@ public class WifiService extends IWifiManager.Stub {
}
public String toString() {
- return "WifiLock{" + mTag + " type=" + mLockMode + " binder=" + mBinder + "}";
+ return "WifiLock{" + mTag + " type=" + mMode + " binder=" + mBinder + "}";
}
}
@@ -1771,7 +1764,7 @@ public class WifiService extends IWifiManager.Stub {
return WifiManager.WIFI_MODE_FULL;
}
for (WifiLock l : mList) {
- if (l.mLockMode == WifiManager.WIFI_MODE_FULL) {
+ if (l.mMode == WifiManager.WIFI_MODE_FULL) {
return WifiManager.WIFI_MODE_FULL;
}
}
@@ -1826,7 +1819,7 @@ public class WifiService extends IWifiManager.Stub {
int uid = Binder.getCallingUid();
long ident = Binder.clearCallingIdentity();
try {
- switch(wifiLock.mLockMode) {
+ switch(wifiLock.mMode) {
case WifiManager.WIFI_MODE_FULL:
++mFullLocksAcquired;
mBatteryStats.noteFullWifiLockAcquired(uid);
@@ -1862,7 +1855,7 @@ public class WifiService extends IWifiManager.Stub {
int uid = Binder.getCallingUid();
long ident = Binder.clearCallingIdentity();
try {
- switch(wifiLock.mLockMode) {
+ switch(wifiLock.mMode) {
case WifiManager.WIFI_MODE_FULL:
++mFullLocksReleased;
mBatteryStats.noteFullWifiLockReleased(uid);
@@ -1881,4 +1874,110 @@ public class WifiService extends IWifiManager.Stub {
updateWifiState();
return hadLock;
}
+
+ private abstract class WifiDeathRecipient
+ implements IBinder.DeathRecipient {
+ String mTag;
+ int mMode;
+ IBinder mBinder;
+
+ WifiDeathRecipient(int mode, String tag, IBinder binder) {
+ super();
+ mTag = tag;
+ mMode = mode;
+ mBinder = binder;
+ try {
+ mBinder.linkToDeath(this, 0);
+ } catch (RemoteException e) {
+ binderDied();
+ }
+ }
+ }
+
+ private class WifiMulticaster extends WifiDeathRecipient {
+ WifiMulticaster(String tag, IBinder binder) {
+ super(Binder.getCallingUid(), tag, binder);
+ }
+
+ public void binderDied() {
+ Log.e(TAG, "WifiMulticaster binderDied");
+ synchronized (mMulticasters) {
+ int i = mMulticasters.indexOf(this);
+ if (i != -1) {
+ removeMulticasterLocked(i, mMode);
+ }
+ }
+ }
+
+ public String toString() {
+ return "WifiMulticaster{" + mTag + " binder=" + mBinder + "}";
+ }
+
+ public int getUid() {
+ return mMode;
+ }
+ }
+
+ public void enableWifiMulticast(IBinder binder, String tag) {
+ enforceChangePermission();
+
+ synchronized (mMulticasters) {
+ mMulticastEnabled++;
+ mMulticasters.add(new WifiMulticaster(tag, binder));
+ // Note that we could call stopPacketFiltering only when
+ // our new size == 1 (first call), but this function won't
+ // be called often and by making the stopPacket call each
+ // time we're less fragile and self-healing.
+ WifiNative.stopPacketFiltering();
+ }
+
+ int uid = Binder.getCallingUid();
+ Long ident = Binder.clearCallingIdentity();
+ try {
+ mBatteryStats.noteWifiMulticastEnabled(uid);
+ } catch (RemoteException e) {
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ public void disableWifiMulticast() {
+ enforceChangePermission();
+
+ int uid = Binder.getCallingUid();
+ synchronized (mMulticasters) {
+ mMulticastDisabled++;
+ int size = mMulticasters.size();
+ for (int i = size - 1; i >= 0; i--) {
+ WifiMulticaster m = mMulticasters.get(i);
+ if ((m != null) && (m.getUid() == uid)) {
+ removeMulticasterLocked(i, uid);
+ }
+ }
+ }
+ }
+
+ private void removeMulticasterLocked(int i, int uid)
+ {
+ mMulticasters.remove(i);
+ if (mMulticasters.size() == 0) {
+ WifiNative.startPacketFiltering();
+ }
+
+ Long ident = Binder.clearCallingIdentity();
+ try {
+ mBatteryStats.noteWifiMulticastDisabled(uid);
+ } catch (RemoteException e) {
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ public boolean isWifiMulticastEnabled() {
+ enforceAccessPermission();
+
+ synchronized (mMulticasters) {
+ return (mMulticasters.size() > 0);
+ }
+ }
}
diff --git a/services/java/com/android/server/am/BatteryStatsService.java b/services/java/com/android/server/am/BatteryStatsService.java
index a21893b..0387be5 100644
--- a/services/java/com/android/server/am/BatteryStatsService.java
+++ b/services/java/com/android/server/am/BatteryStatsService.java
@@ -261,6 +261,20 @@ public final class BatteryStatsService extends IBatteryStats.Stub {
}
}
+ public void noteWifiMulticastEnabled(int uid) {
+ enforceCallingPermission();
+ synchronized (mStats) {
+ mStats.noteWifiMulticastEnabledLocked(uid);
+ }
+ }
+
+ public void noteWifiMulticastDisabled(int uid) {
+ enforceCallingPermission();
+ synchronized (mStats) {
+ mStats.noteWifiMulticastDisabledLocked(uid);
+ }
+ }
+
public boolean isOnBattery() {
return mStats.isOnBattery();
}
diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl
index f9a0845..00829d6 100644
--- a/wifi/java/android/net/wifi/IWifiManager.aidl
+++ b/wifi/java/android/net/wifi/IWifiManager.aidl
@@ -69,5 +69,11 @@ interface IWifiManager
boolean acquireWifiLock(IBinder lock, int lockType, String tag);
boolean releaseWifiLock(IBinder lock);
+
+ boolean isWifiMulticastEnabled();
+
+ void enableWifiMulticast(IBinder binder, String tag);
+
+ void disableWifiMulticast();
}
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index a51e88f..658a7b2 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -823,4 +823,65 @@ public class WifiManager {
public WifiLock createWifiLock(String tag) {
return new WifiLock(WIFI_MODE_FULL, tag);
}
+
+ /**
+ * Check multicast filter status.
+ *
+ * @return true if multicast packets are allowed.
+ *
+ * @hide pending API council approval
+ */
+ public boolean isWifiMulticastEnabled() {
+ try {
+ return mService.isWifiMulticastEnabled();
+ } catch (RemoteException e) {
+ 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 #disableWifiMulticast
+ *
+ * @hide pending API council approval
+ */
+ public boolean enableWifiMulticast(String tag) {
+ try {
+ mService.enableWifiMulticast(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 #enableWifiMulticast
+ *
+ * @hide pending API council approval
+ */
+ public boolean disableWifiMulticast() {
+ try {
+ mService.disableWifiMulticast();
+ 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 6ea35f5..64084cf 100644
--- a/wifi/java/android/net/wifi/WifiStateTracker.java
+++ b/wifi/java/android/net/wifi/WifiStateTracker.java
@@ -732,15 +732,19 @@ public class WifiStateTracker extends NetworkStateTracker {
/*
* Filter out multicast packets. This saves battery power, since
* the CPU doesn't have to spend time processing packets that
- * are going to end up being thrown away. Obviously, if we
- * ever want to support multicast, this will have to change.
+ * are going to end up being thrown away.
+ *
+ * Note that rather than turn this off directly, we use the
+ * public api - this keeps us all in sync - turn multicast on
+ * first and then off.. if nobody else wants it on it'll be
+ * off then and it's all synchronized within the API.
*/
+ mWM.enableWifiMulticast("WifiStateTracker");
+ mWM.disableWifiMulticast();
+
if (mBluetoothA2dp == null) {
mBluetoothA2dp = new BluetoothA2dp(mContext);
}
- synchronized (this) {
- WifiNative.startPacketFiltering();
- }
checkIsBluetoothPlaying();
break;