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

Commit a3225e20 authored by Jeff Brown's avatar Jeff Brown Committed by The Android Automerger
Browse files

Fix a deadlock involving BatteryService.

The PowerManager may call into the BatteryService while
holding its locks.  We need to be careful that the BatteryService
doesn't call into other services, particularly the ActivityManager
while holding its own locks.

Bug: 7298218
Change-Id: Ibf8ab13224f204a9857825265e864f93583bce8e
parent b6230541
Loading
Loading
Loading
Loading
+74 −24
Original line number Original line Diff line number Diff line
@@ -27,6 +27,7 @@ import android.content.pm.PackageManager;
import android.os.BatteryManager;
import android.os.BatteryManager;
import android.os.Binder;
import android.os.Binder;
import android.os.FileUtils;
import android.os.FileUtils;
import android.os.Handler;
import android.os.IBinder;
import android.os.IBinder;
import android.os.DropBoxManager;
import android.os.DropBoxManager;
import android.os.RemoteException;
import android.os.RemoteException;
@@ -66,6 +67,14 @@ import java.io.PrintWriter;
 * <p>&quot;temperature&quot; - int, current battery temperature in tenths of
 * <p>&quot;temperature&quot; - int, current battery temperature in tenths of
 * a degree Centigrade</p>
 * a degree Centigrade</p>
 * <p>&quot;technology&quot; - String, the type of battery installed, e.g. "Li-ion"</p>
 * <p>&quot;technology&quot; - String, the type of battery installed, e.g. "Li-ion"</p>
 *
 * <p>
 * The battery service may be called by the power manager while holding its locks so
 * we take care to post all outcalls into the activity manager to a handler.
 *
 * FIXME: Ideally the power manager would perform all of its calls into the battery
 * service asynchronously itself.
 * </p>
 */
 */
public final class BatteryService extends Binder {
public final class BatteryService extends Binder {
    private static final String TAG = BatteryService.class.getSimpleName();
    private static final String TAG = BatteryService.class.getSimpleName();
@@ -89,6 +98,7 @@ public final class BatteryService extends Binder {


    private final Context mContext;
    private final Context mContext;
    private final IBatteryStats mBatteryStats;
    private final IBatteryStats mBatteryStats;
    private final Handler mHandler;


    private final Object mLock = new Object();
    private final Object mLock = new Object();


@@ -137,6 +147,7 @@ public final class BatteryService extends Binder {


    public BatteryService(Context context, LightsService lights) {
    public BatteryService(Context context, LightsService lights) {
        mContext = context;
        mContext = context;
        mHandler = new Handler(true /*async*/);
        mLed = new Led(context, lights);
        mLed = new Led(context, lights);
        mBatteryStats = BatteryStatsService.getService();
        mBatteryStats = BatteryStatsService.getService();


@@ -228,27 +239,39 @@ public final class BatteryService extends Binder {
    private void shutdownIfNoPowerLocked() {
    private void shutdownIfNoPowerLocked() {
        // shut down gracefully if our battery is critically low and we are not powered.
        // shut down gracefully if our battery is critically low and we are not powered.
        // wait until the system has booted before attempting to display the shutdown dialog.
        // wait until the system has booted before attempting to display the shutdown dialog.
        if (mBatteryLevel == 0 && !isPoweredLocked(BatteryManager.BATTERY_PLUGGED_ANY)
        if (mBatteryLevel == 0 && !isPoweredLocked(BatteryManager.BATTERY_PLUGGED_ANY)) {
                && ActivityManagerNative.isSystemReady()) {
            mHandler.post(new Runnable() {
                @Override
                public void run() {
                    if (ActivityManagerNative.isSystemReady()) {
                        Intent intent = new Intent(Intent.ACTION_REQUEST_SHUTDOWN);
                        Intent intent = new Intent(Intent.ACTION_REQUEST_SHUTDOWN);
                        intent.putExtra(Intent.EXTRA_KEY_CONFIRM, false);
                        intent.putExtra(Intent.EXTRA_KEY_CONFIRM, false);
                        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                        mContext.startActivityAsUser(intent, UserHandle.CURRENT);
                        mContext.startActivityAsUser(intent, UserHandle.CURRENT);
                    }
                    }
                }
                }
            });
        }
    }


    private void shutdownIfOverTempLocked() {
    private void shutdownIfOverTempLocked() {
        // shut down gracefully if temperature is too high (> 68.0C by default)
        // shut down gracefully if temperature is too high (> 68.0C by default)
        // wait until the system has booted before attempting to display the
        // wait until the system has booted before attempting to display the
        // shutdown dialog.
        // shutdown dialog.
        if (mBatteryTemperature > mShutdownBatteryTemperature
        if (mBatteryTemperature > mShutdownBatteryTemperature) {
                && ActivityManagerNative.isSystemReady()) {
            mHandler.post(new Runnable() {
                @Override
                public void run() {
                    if (ActivityManagerNative.isSystemReady()) {
                        Intent intent = new Intent(Intent.ACTION_REQUEST_SHUTDOWN);
                        Intent intent = new Intent(Intent.ACTION_REQUEST_SHUTDOWN);
                        intent.putExtra(Intent.EXTRA_KEY_CONFIRM, false);
                        intent.putExtra(Intent.EXTRA_KEY_CONFIRM, false);
                        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                        mContext.startActivityAsUser(intent, UserHandle.CURRENT);
                        mContext.startActivityAsUser(intent, UserHandle.CURRENT);
                    }
                    }
                }
                }
            });
        }
    }


    private void updateLocked() {
    private void updateLocked() {
        if (!mUpdatesStopped) {
        if (!mUpdatesStopped) {
@@ -373,26 +396,48 @@ public final class BatteryService extends Binder {
            // Separate broadcast is sent for power connected / not connected
            // Separate broadcast is sent for power connected / not connected
            // since the standard intent will not wake any applications and some
            // since the standard intent will not wake any applications and some
            // applications may want to have smart behavior based on this.
            // applications may want to have smart behavior based on this.
            Intent statusIntent = new Intent();
            statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
            if (mPlugType != 0 && mLastPlugType == 0) {
            if (mPlugType != 0 && mLastPlugType == 0) {
                statusIntent.setAction(Intent.ACTION_POWER_CONNECTED);
                mHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        Intent statusIntent = new Intent(Intent.ACTION_POWER_CONNECTED);
                        statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
                        mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL);
                        mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL);
                    }
                    }
                });
            }
            else if (mPlugType == 0 && mLastPlugType != 0) {
            else if (mPlugType == 0 && mLastPlugType != 0) {
                statusIntent.setAction(Intent.ACTION_POWER_DISCONNECTED);
                mHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        Intent statusIntent = new Intent(Intent.ACTION_POWER_DISCONNECTED);
                        statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
                        mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL);
                        mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL);
                    }
                    }
                });
            }


            if (sendBatteryLow) {
            if (sendBatteryLow) {
                mSentLowBatteryBroadcast = true;
                mSentLowBatteryBroadcast = true;
                statusIntent.setAction(Intent.ACTION_BATTERY_LOW);
                mHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        Intent statusIntent = new Intent(Intent.ACTION_BATTERY_LOW);
                        statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
                        mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL);
                        mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL);
                    }
                });
            } else if (mSentLowBatteryBroadcast && mLastBatteryLevel >= mLowBatteryCloseWarningLevel) {
            } else if (mSentLowBatteryBroadcast && mLastBatteryLevel >= mLowBatteryCloseWarningLevel) {
                mSentLowBatteryBroadcast = false;
                mSentLowBatteryBroadcast = false;
                statusIntent.setAction(Intent.ACTION_BATTERY_OKAY);
                mHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        Intent statusIntent = new Intent(Intent.ACTION_BATTERY_OKAY);
                        statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
                        mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL);
                        mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL);
                    }
                    }
                });
            }


            // Update the battery LED
            // Update the battery LED
            mLed.updateLightsLocked();
            mLed.updateLightsLocked();
@@ -416,7 +461,7 @@ public final class BatteryService extends Binder {


    private void sendIntentLocked() {
    private void sendIntentLocked() {
        //  Pack up the values and broadcast them to everyone
        //  Pack up the values and broadcast them to everyone
        Intent intent = new Intent(Intent.ACTION_BATTERY_CHANGED);
        final Intent intent = new Intent(Intent.ACTION_BATTERY_CHANGED);
        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
                | Intent.FLAG_RECEIVER_REPLACE_PENDING);
                | Intent.FLAG_RECEIVER_REPLACE_PENDING);


@@ -446,8 +491,13 @@ public final class BatteryService extends Binder {
                    ", icon:" + icon  + ", invalid charger:" + mInvalidCharger);
                    ", icon:" + icon  + ", invalid charger:" + mInvalidCharger);
        }
        }


        mHandler.post(new Runnable() {
            @Override
            public void run() {
                ActivityManagerNative.broadcastStickyIntent(intent, null, UserHandle.USER_ALL);
                ActivityManagerNative.broadcastStickyIntent(intent, null, UserHandle.USER_ALL);
            }
            }
        });
    }


    private void logBatteryStatsLocked() {
    private void logBatteryStatsLocked() {
        IBinder batteryInfoService = ServiceManager.getService(BATTERY_STATS_SERVICE_NAME);
        IBinder batteryInfoService = ServiceManager.getService(BATTERY_STATS_SERVICE_NAME);