Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit dbcc8a22 authored by Jeff Brown's avatar Jeff Brown
Browse files

Track wireless charger detector timeout explicitly.

Previously we relied on having a continue stream of sensor
events from which to detect whether the device is moving or
at rest.  However, if the sensor HAL is broken in some way
then we might not receive enough sensor events to actually
finish the detection process.  When this happens, we'll
just sit there holding a wakelock indefinitely.

Instead of relying on the sensor event stream, post a delayed
message to explicitly finish detection.

Bug: 10769163
Change-Id: Ia2ed66fe5e7c41a8832df76da9104c13554e1398
parent 2e05ec32
Loading
Loading
Loading
Loading
+2 −1
Original line number Original line Diff line number Diff line
@@ -453,7 +453,8 @@ public final class PowerManagerService extends IPowerManager.Stub
                    mDisplayPowerControllerCallbacks, mHandler);
                    mDisplayPowerControllerCallbacks, mHandler);


            mWirelessChargerDetector = new WirelessChargerDetector(sensorManager,
            mWirelessChargerDetector = new WirelessChargerDetector(sensorManager,
                    createSuspendBlockerLocked("PowerManagerService.WirelessChargerDetector"));
                    createSuspendBlockerLocked("PowerManagerService.WirelessChargerDetector"),
                    mHandler);
            mSettingsObserver = new SettingsObserver(mHandler);
            mSettingsObserver = new SettingsObserver(mHandler);
            mAttentionLight = mLightsService.getLight(LightsService.LIGHT_ID_ATTENTION);
            mAttentionLight = mLightsService.getLight(LightsService.LIGHT_ID_ATTENTION);


+69 −48
Original line number Original line Diff line number Diff line
@@ -21,8 +21,11 @@ import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.hardware.SensorManager;
import android.os.BatteryManager;
import android.os.BatteryManager;
import android.os.Handler;
import android.os.Message;
import android.os.SystemClock;
import android.os.SystemClock;
import android.util.Slog;
import android.util.Slog;
import android.util.TimeUtils;


import java.io.PrintWriter;
import java.io.PrintWriter;


@@ -70,12 +73,12 @@ final class WirelessChargerDetector {
    private static final String TAG = "WirelessChargerDetector";
    private static final String TAG = "WirelessChargerDetector";
    private static final boolean DEBUG = false;
    private static final boolean DEBUG = false;


    // Number of nanoseconds per millisecond.
    private static final long NANOS_PER_MS = 1000000;

    // The minimum amount of time to spend watching the sensor before making
    // The minimum amount of time to spend watching the sensor before making
    // a determination of whether movement occurred.
    // a determination of whether movement occurred.
    private static final long SETTLE_TIME_NANOS = 500 * NANOS_PER_MS;
    private static final long SETTLE_TIME_MILLIS = 800;

    // The sensor sampling interval.
    private static final int SAMPLING_INTERVAL_MILLIS = 50;


    // The minimum number of samples that must be collected.
    // The minimum number of samples that must be collected.
    private static final int MIN_SAMPLES = 3;
    private static final int MIN_SAMPLES = 3;
@@ -97,6 +100,7 @@ final class WirelessChargerDetector {


    private final SensorManager mSensorManager;
    private final SensorManager mSensorManager;
    private final SuspendBlocker mSuspendBlocker;
    private final SuspendBlocker mSuspendBlocker;
    private final Handler mHandler;


    // The gravity sensor, or null if none.
    // The gravity sensor, or null if none.
    private Sensor mGravitySensor;
    private Sensor mGravitySensor;
@@ -116,6 +120,9 @@ final class WirelessChargerDetector {
    // The suspend blocker is held while this is the case.
    // The suspend blocker is held while this is the case.
    private boolean mDetectionInProgress;
    private boolean mDetectionInProgress;


    // The time when detection was last performed.
    private long mDetectionStartTime;

    // True if the rest position should be updated if at rest.
    // True if the rest position should be updated if at rest.
    // Otherwise, the current rest position is simply checked and cleared if movement
    // Otherwise, the current rest position is simply checked and cleared if movement
    // is detected but no new rest position is stored.
    // is detected but no new rest position is stored.
@@ -127,18 +134,17 @@ final class WirelessChargerDetector {
    // The number of samples collected that showed evidence of not being at rest.
    // The number of samples collected that showed evidence of not being at rest.
    private int mMovingSamples;
    private int mMovingSamples;


    // The time and value of the first sample that was collected.
    // The value of the first sample that was collected.
    private long mFirstSampleTime;
    private float mFirstSampleX, mFirstSampleY, mFirstSampleZ;
    private float mFirstSampleX, mFirstSampleY, mFirstSampleZ;


    // The time and value of the last sample that was collected (for debugging only).
    // The value of the last sample that was collected.
    private long mLastSampleTime;
    private float mLastSampleX, mLastSampleY, mLastSampleZ;
    private float mLastSampleX, mLastSampleY, mLastSampleZ;


    public WirelessChargerDetector(SensorManager sensorManager,
    public WirelessChargerDetector(SensorManager sensorManager,
            SuspendBlocker suspendBlocker) {
            SuspendBlocker suspendBlocker, Handler handler) {
        mSensorManager = sensorManager;
        mSensorManager = sensorManager;
        mSuspendBlocker = suspendBlocker;
        mSuspendBlocker = suspendBlocker;
        mHandler = handler;


        mGravitySensor = sensorManager.getDefaultSensor(Sensor.TYPE_GRAVITY);
        mGravitySensor = sensorManager.getDefaultSensor(Sensor.TYPE_GRAVITY);
    }
    }
@@ -152,13 +158,13 @@ final class WirelessChargerDetector {
            pw.println("  mAtRest=" + mAtRest);
            pw.println("  mAtRest=" + mAtRest);
            pw.println("  mRestX=" + mRestX + ", mRestY=" + mRestY + ", mRestZ=" + mRestZ);
            pw.println("  mRestX=" + mRestX + ", mRestY=" + mRestY + ", mRestZ=" + mRestZ);
            pw.println("  mDetectionInProgress=" + mDetectionInProgress);
            pw.println("  mDetectionInProgress=" + mDetectionInProgress);
            pw.println("  mDetectionStartTime=" + (mDetectionStartTime == 0 ? "0 (never)"
                    : TimeUtils.formatUptime(mDetectionStartTime)));
            pw.println("  mMustUpdateRestPosition=" + mMustUpdateRestPosition);
            pw.println("  mMustUpdateRestPosition=" + mMustUpdateRestPosition);
            pw.println("  mTotalSamples=" + mTotalSamples);
            pw.println("  mTotalSamples=" + mTotalSamples);
            pw.println("  mMovingSamples=" + mMovingSamples);
            pw.println("  mMovingSamples=" + mMovingSamples);
            pw.println("  mFirstSampleTime=" + mFirstSampleTime);
            pw.println("  mFirstSampleX=" + mFirstSampleX
            pw.println("  mFirstSampleX=" + mFirstSampleX
                    + ", mFirstSampleY=" + mFirstSampleY + ", mFirstSampleZ=" + mFirstSampleZ);
                    + ", mFirstSampleY=" + mFirstSampleY + ", mFirstSampleZ=" + mFirstSampleZ);
            pw.println("  mLastSampleTime=" + mLastSampleTime);
            pw.println("  mLastSampleX=" + mLastSampleX
            pw.println("  mLastSampleX=" + mLastSampleX
                    + ", mLastSampleY=" + mLastSampleY + ", mLastSampleZ=" + mLastSampleZ);
                    + ", mLastSampleY=" + mLastSampleY + ", mLastSampleZ=" + mLastSampleZ);
        }
        }
@@ -217,22 +223,56 @@ final class WirelessChargerDetector {
    private void startDetectionLocked() {
    private void startDetectionLocked() {
        if (!mDetectionInProgress && mGravitySensor != null) {
        if (!mDetectionInProgress && mGravitySensor != null) {
            if (mSensorManager.registerListener(mListener, mGravitySensor,
            if (mSensorManager.registerListener(mListener, mGravitySensor,
                    SensorManager.SENSOR_DELAY_UI)) {
                    SAMPLING_INTERVAL_MILLIS * 1000)) {
                mSuspendBlocker.acquire();
                mSuspendBlocker.acquire();
                mDetectionInProgress = true;
                mDetectionInProgress = true;
                mDetectionStartTime = SystemClock.uptimeMillis();
                mTotalSamples = 0;
                mTotalSamples = 0;
                mMovingSamples = 0;
                mMovingSamples = 0;

                Message msg = Message.obtain(mHandler, mSensorTimeout);
                msg.setAsynchronous(true);
                mHandler.sendMessageDelayed(msg, SETTLE_TIME_MILLIS);
            }
            }
        }
        }
    }
    }


    private void processSample(long timeNanos, float x, float y, float z) {
    private void finishDetectionLocked() {
        synchronized (mLock) {
        if (mDetectionInProgress) {
            if (!mDetectionInProgress) {
            mSensorManager.unregisterListener(mListener);
                return;
            mHandler.removeCallbacks(mSensorTimeout);

            if (mMustUpdateRestPosition) {
                clearAtRestLocked();
                if (mTotalSamples < MIN_SAMPLES) {
                    Slog.w(TAG, "Wireless charger detector is broken.  Only received "
                            + mTotalSamples + " samples from the gravity sensor but we "
                            + "need at least " + MIN_SAMPLES + " and we expect to see "
                            + "about " + SETTLE_TIME_MILLIS / SAMPLING_INTERVAL_MILLIS
                            + " on average.");
                } else if (mMovingSamples == 0) {
                    mAtRest = true;
                    mRestX = mLastSampleX;
                    mRestY = mLastSampleY;
                    mRestZ = mLastSampleZ;
                }
                mMustUpdateRestPosition = false;
            }

            if (DEBUG) {
                Slog.d(TAG, "New state: mAtRest=" + mAtRest
                        + ", mRestX=" + mRestX + ", mRestY=" + mRestY + ", mRestZ=" + mRestZ
                        + ", mTotalSamples=" + mTotalSamples
                        + ", mMovingSamples=" + mMovingSamples);
            }
            }


            mLastSampleTime = timeNanos;
            mDetectionInProgress = false;
            mSuspendBlocker.release();
        }
    }

    private void processSampleLocked(float x, float y, float z) {
        if (mDetectionInProgress) {
            mLastSampleX = x;
            mLastSampleX = x;
            mLastSampleY = y;
            mLastSampleY = y;
            mLastSampleZ = z;
            mLastSampleZ = z;
@@ -240,7 +280,6 @@ final class WirelessChargerDetector {
            mTotalSamples += 1;
            mTotalSamples += 1;
            if (mTotalSamples == 1) {
            if (mTotalSamples == 1) {
                // Save information about the first sample collected.
                // Save information about the first sample collected.
                mFirstSampleTime = timeNanos;
                mFirstSampleX = x;
                mFirstSampleX = x;
                mFirstSampleY = y;
                mFirstSampleY = y;
                mFirstSampleZ = z;
                mFirstSampleZ = z;
@@ -260,32 +299,6 @@ final class WirelessChargerDetector {
                }
                }
                clearAtRestLocked();
                clearAtRestLocked();
            }
            }

            // Save the result when done.
            if (timeNanos - mFirstSampleTime >= SETTLE_TIME_NANOS
                    && mTotalSamples >= MIN_SAMPLES) {
                mSensorManager.unregisterListener(mListener);
                if (mMustUpdateRestPosition) {
                    if (mMovingSamples == 0) {
                        mAtRest = true;
                        mRestX = x;
                        mRestY = y;
                        mRestZ = z;
                    } else {
                        clearAtRestLocked();
                    }
                    mMustUpdateRestPosition = false;
                }
                mDetectionInProgress = false;
                mSuspendBlocker.release();

                if (DEBUG) {
                    Slog.d(TAG, "New state: mAtRest=" + mAtRest
                            + ", mRestX=" + mRestX + ", mRestY=" + mRestY + ", mRestZ=" + mRestZ
                            + ", mTotalSamples=" + mTotalSamples
                            + ", mMovingSamples=" + mMovingSamples);
                }
            }
        }
        }
    }
    }


@@ -323,14 +336,22 @@ final class WirelessChargerDetector {
    private final SensorEventListener mListener = new SensorEventListener() {
    private final SensorEventListener mListener = new SensorEventListener() {
        @Override
        @Override
        public void onSensorChanged(SensorEvent event) {
        public void onSensorChanged(SensorEvent event) {
            // We use SystemClock.elapsedRealtimeNanos() instead of event.timestamp because
            synchronized (mLock) {
            // on some devices the sensor HAL may produce timestamps that are not monotonic.
                processSampleLocked(event.values[0], event.values[1], event.values[2]);
            processSample(SystemClock.elapsedRealtimeNanos(),
            }
                    event.values[0], event.values[1], event.values[2]);
        }
        }


        @Override
        @Override
        public void onAccuracyChanged(Sensor sensor, int accuracy) {
        public void onAccuracyChanged(Sensor sensor, int accuracy) {
        }
        }
    };
    };

    private final Runnable mSensorTimeout = new Runnable() {
        @Override
        public void run() {
            synchronized (mLock) {
                finishDetectionLocked();
            }
        }
    };
}
}