diff options
author | Mathias Agopian <mathias@google.com> | 2010-03-01 14:37:50 -0800 |
---|---|---|
committer | Mathias Agopian <mathias@google.com> | 2010-03-01 18:31:16 -0800 |
commit | 69f22feb8540576d2a2e9d32f9c86ebbbf309409 (patch) | |
tree | 3b2b0225dd8adbf10a1135cf13cc212face5eca2 | |
parent | 42c79880b0c19dfbcd8589d89d35fcedb1a7c9da (diff) | |
download | frameworks_base-69f22feb8540576d2a2e9d32f9c86ebbbf309409.zip frameworks_base-69f22feb8540576d2a2e9d32f9c86ebbbf309409.tar.gz frameworks_base-69f22feb8540576d2a2e9d32f9c86ebbbf309409.tar.bz2 |
fix [2476230] sensor battery stats could get out of sync if an error occurs
Fixed a few problems with the SensorService:
- a race condition when talking to the BatteryStatService
- only report changes to BatteryStatService when there are no errors
(ie: when a change actually happens)
- tell the BatteryStatService when a sensor is deactivated because its
client died
- rewrite enableSensor() so it's readable
- implement dump() so dumpsys will display some infos about active sensors
- recompute the delay properly when sensors are added/removed
-rw-r--r-- | services/java/com/android/server/SensorService.java | 192 |
1 files changed, 134 insertions, 58 deletions
diff --git a/services/java/com/android/server/SensorService.java b/services/java/com/android/server/SensorService.java index 01d64a7..9f5718f 100644 --- a/services/java/com/android/server/SensorService.java +++ b/services/java/com/android/server/SensorService.java @@ -24,7 +24,11 @@ import android.os.RemoteException; import android.os.IBinder; import android.util.Config; import android.util.Slog; +import android.util.PrintWriterPrinter; +import android.util.Printer; +import java.io.FileDescriptor; +import java.io.PrintWriter; import java.util.ArrayList; import com.android.internal.app.IBatteryStats; @@ -43,6 +47,7 @@ class SensorService extends ISensorService.Stub { private static final boolean DEBUG = false; private static final boolean localLOGV = DEBUG ? Config.LOGD : Config.LOGV; private static final int SENSOR_DISABLE = -1; + private int mCurrentDelay = 0; /** * Battery statistics to be updated when sensors are enabled and disabled. @@ -51,17 +56,19 @@ class SensorService extends ISensorService.Stub { private final class Listener implements IBinder.DeathRecipient { final IBinder mToken; + final int mUid; int mSensors = 0; int mDelay = 0x7FFFFFFF; - Listener(IBinder token) { + Listener(IBinder token, int uid) { mToken = token; + mUid = uid; } void addSensor(int sensor, int delay) { mSensors |= (1<<sensor); - if (mDelay > delay) + if (delay < mDelay) mDelay = delay; } @@ -83,16 +90,20 @@ class SensorService extends ISensorService.Stub { for (int sensor=0 ; sensor<32 && mSensors!=0 ; sensor++) { if (hasSensor(sensor)) { removeSensor(sensor); + deactivateIfUnusedLocked(sensor); try { - deactivateIfUnusedLocked(sensor); + mBatteryStats.noteStopSensor(mUid, sensor); } catch (RemoteException e) { - Slog.w(TAG, "RemoteException in binderDied"); + // oops. not a big deal. } } } if (mListeners.size() == 0) { _sensors_control_wake(); _sensors_control_close(); + } else { + // TODO: we should recalculate the delay, since removing + // a listener may increase the overall rate. } mListeners.notify(); } @@ -113,86 +124,151 @@ class SensorService extends ISensorService.Stub { } public boolean enableSensor(IBinder binder, String name, int sensor, int enable) - throws RemoteException { - if (localLOGV) Slog.d(TAG, "enableSensor " + name + "(#" + sensor + ") " + enable); + throws RemoteException { - // Inform battery statistics service of status change - int uid = Binder.getCallingUid(); - long identity = Binder.clearCallingIdentity(); - if (enable == SENSOR_DISABLE) { - mBatteryStats.noteStopSensor(uid, sensor); - } else { - mBatteryStats.noteStartSensor(uid, sensor); - } - Binder.restoreCallingIdentity(identity); + if (localLOGV) Slog.d(TAG, "enableSensor " + name + "(#" + sensor + ") " + enable); if (binder == null) { - Slog.w(TAG, "listener is null (sensor=" + name + ", id=" + sensor + ")"); + Slog.e(TAG, "listener is null (sensor=" + name + ", id=" + sensor + ")"); + return false; + } + + if (enable < 0 && (enable != SENSOR_DISABLE)) { + Slog.e(TAG, "invalid enable parameter (enable=" + enable + + ", sensor=" + name + ", id=" + sensor + ")"); return false; } + boolean res; + int uid = Binder.getCallingUid(); synchronized(mListeners) { - if (enable!=SENSOR_DISABLE && !_sensors_control_activate(sensor, true)) { + res = enableSensorInternalLocked(binder, uid, name, sensor, enable); + if (res == true) { + // Inform battery statistics service of status change + long identity = Binder.clearCallingIdentity(); + if (enable == SENSOR_DISABLE) { + mBatteryStats.noteStopSensor(uid, sensor); + } else { + mBatteryStats.noteStartSensor(uid, sensor); + } + Binder.restoreCallingIdentity(identity); + } + } + return res; + } + + private boolean enableSensorInternalLocked(IBinder binder, int uid, + String name, int sensor, int enable) throws RemoteException { + + // check if we have this listener + Listener l = null; + for (Listener listener : mListeners) { + if (binder == listener.mToken) { + l = listener; + break; + } + } + + if (enable != SENSOR_DISABLE) { + // Activate the requested sensor + if (_sensors_control_activate(sensor, true) == false) { Slog.w(TAG, "could not enable sensor " + sensor); return false; } - - Listener l = null; - int minDelay = enable; - for (Listener listener : mListeners) { - if (binder == listener.mToken) { - l = listener; - } - if (minDelay > listener.mDelay) - minDelay = listener.mDelay; - } - - if (l == null && enable!=SENSOR_DISABLE) { - l = new Listener(binder); + + if (l == null) { + /* + * we don't have a listener for this binder yet, so + * create a new one and add it to the list. + */ + l = new Listener(binder, uid); binder.linkToDeath(l, 0); mListeners.add(l); mListeners.notify(); } - + + // take note that this sensor is now used by this client + l.addSensor(sensor, enable); + + } else { + if (l == null) { - // by construction, this means we're disabling a listener we - // don't know about... - Slog.w(TAG, "listener with binder " + binder + - ", doesn't exist (sensor=" + name + ", id=" + sensor + ")"); + /* + * This client isn't in the list, this usually happens + * when enabling the sensor failed, but the client + * didn't handle the error and later tries to shut that + * sensor off. + */ + Slog.w(TAG, "listener with binder " + binder + + ", doesn't exist (sensor=" + name + + ", id=" + sensor + ")"); return false; } - - if (minDelay >= 0) { - _sensors_control_set_delay(minDelay); - } - - if (enable != SENSOR_DISABLE) { - l.addSensor(sensor, enable); - } else { - l.removeSensor(sensor); - deactivateIfUnusedLocked(sensor); - if (l.mSensors == 0) { - mListeners.remove(l); - binder.unlinkToDeath(l, 0); - mListeners.notify(); + + // remove this sensor from this client + l.removeSensor(sensor); + + // see if we need to deactivate this sensors= + deactivateIfUnusedLocked(sensor); + + // if the listener doesn't have any more sensors active + // we can get rid of it + if (l.mSensors == 0) { + // we won't need this death notification anymore + binder.unlinkToDeath(l, 0); + // remove the listener from the list + mListeners.remove(l); + // and if the list is empty, turn off the whole sensor h/w + if (mListeners.size() == 0) { + _sensors_control_wake(); + _sensors_control_close(); } + mListeners.notify(); } - - if (mListeners.size() == 0) { - _sensors_control_wake(); - _sensors_control_close(); - } - } + } + + // calculate and set the new delay + int minDelay = 0x7FFFFFFF; + for (Listener listener : mListeners) { + if (listener.mDelay < minDelay) + minDelay = listener.mDelay; + } + if (minDelay != 0x7FFFFFFF) { + mCurrentDelay = minDelay; + _sensors_control_set_delay(minDelay); + } + return true; } - private void deactivateIfUnusedLocked(int sensor) throws RemoteException { + private void deactivateIfUnusedLocked(int sensor) { int size = mListeners.size(); for (int i=0 ; i<size ; i++) { - if (mListeners.get(i).hasSensor(sensor)) + if (mListeners.get(i).hasSensor(sensor)) { + // this sensor is still in use, don't turn it off return; + } + } + if (_sensors_control_activate(sensor, false) == false) { + Slog.w(TAG, "could not disable sensor " + sensor); + } + } + + @Override + protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + synchronized (mListeners) { + Printer pr = new PrintWriterPrinter(pw); + int c = 0; + pr.println(mListeners.size() + " listener(s), delay=" + mCurrentDelay + " ms"); + for (Listener l : mListeners) { + pr.println("listener[" + c + "] " + + "sensors=0x" + Integer.toString(l.mSensors, 16) + + ", uid=" + l.mUid + + ", delay=" + + l.mDelay + " ms"); + c++; + } } - _sensors_control_activate(sensor, false); } private ArrayList<Listener> mListeners = new ArrayList<Listener>(); |