Skip to content

Commit 605ea69

Browse files
author
Jeff Brown
committed
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
1 parent 6aaf295 commit 605ea69

File tree

1 file changed

+74
-24
lines changed

1 file changed

+74
-24
lines changed

services/java/com/android/server/BatteryService.java

Lines changed: 74 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import android.os.BatteryManager;
2828
import android.os.Binder;
2929
import android.os.FileUtils;
30+
import android.os.Handler;
3031
import android.os.IBinder;
3132
import android.os.DropBoxManager;
3233
import android.os.RemoteException;
@@ -66,6 +67,14 @@
6667
* <p>&quot;temperature&quot; - int, current battery temperature in tenths of
6768
* a degree Centigrade</p>
6869
* <p>&quot;technology&quot; - String, the type of battery installed, e.g. "Li-ion"</p>
70+
*
71+
* <p>
72+
* The battery service may be called by the power manager while holding its locks so
73+
* we take care to post all outcalls into the activity manager to a handler.
74+
*
75+
* FIXME: Ideally the power manager would perform all of its calls into the battery
76+
* service asynchronously itself.
77+
* </p>
6978
*/
7079
public final class BatteryService extends Binder {
7180
private static final String TAG = BatteryService.class.getSimpleName();
@@ -89,6 +98,7 @@ public final class BatteryService extends Binder {
8998

9099
private final Context mContext;
91100
private final IBatteryStats mBatteryStats;
101+
private final Handler mHandler;
92102

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

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

138148
public BatteryService(Context context, LightsService lights) {
139149
mContext = context;
150+
mHandler = new Handler(true /*async*/);
140151
mLed = new Led(context, lights);
141152
mBatteryStats = BatteryStatsService.getService();
142153

@@ -228,25 +239,37 @@ public boolean isBatteryLow() {
228239
private void shutdownIfNoPowerLocked() {
229240
// shut down gracefully if our battery is critically low and we are not powered.
230241
// wait until the system has booted before attempting to display the shutdown dialog.
231-
if (mBatteryLevel == 0 && !isPoweredLocked(BatteryManager.BATTERY_PLUGGED_ANY)
232-
&& ActivityManagerNative.isSystemReady()) {
233-
Intent intent = new Intent(Intent.ACTION_REQUEST_SHUTDOWN);
234-
intent.putExtra(Intent.EXTRA_KEY_CONFIRM, false);
235-
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
236-
mContext.startActivityAsUser(intent, UserHandle.CURRENT);
242+
if (mBatteryLevel == 0 && !isPoweredLocked(BatteryManager.BATTERY_PLUGGED_ANY)) {
243+
mHandler.post(new Runnable() {
244+
@Override
245+
public void run() {
246+
if (ActivityManagerNative.isSystemReady()) {
247+
Intent intent = new Intent(Intent.ACTION_REQUEST_SHUTDOWN);
248+
intent.putExtra(Intent.EXTRA_KEY_CONFIRM, false);
249+
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
250+
mContext.startActivityAsUser(intent, UserHandle.CURRENT);
251+
}
252+
}
253+
});
237254
}
238255
}
239256

240257
private void shutdownIfOverTempLocked() {
241258
// shut down gracefully if temperature is too high (> 68.0C by default)
242259
// wait until the system has booted before attempting to display the
243260
// shutdown dialog.
244-
if (mBatteryTemperature > mShutdownBatteryTemperature
245-
&& ActivityManagerNative.isSystemReady()) {
246-
Intent intent = new Intent(Intent.ACTION_REQUEST_SHUTDOWN);
247-
intent.putExtra(Intent.EXTRA_KEY_CONFIRM, false);
248-
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
249-
mContext.startActivityAsUser(intent, UserHandle.CURRENT);
261+
if (mBatteryTemperature > mShutdownBatteryTemperature) {
262+
mHandler.post(new Runnable() {
263+
@Override
264+
public void run() {
265+
if (ActivityManagerNative.isSystemReady()) {
266+
Intent intent = new Intent(Intent.ACTION_REQUEST_SHUTDOWN);
267+
intent.putExtra(Intent.EXTRA_KEY_CONFIRM, false);
268+
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
269+
mContext.startActivityAsUser(intent, UserHandle.CURRENT);
270+
}
271+
}
272+
});
250273
}
251274
}
252275

@@ -373,25 +396,47 @@ private void processValuesLocked() {
373396
// Separate broadcast is sent for power connected / not connected
374397
// since the standard intent will not wake any applications and some
375398
// applications may want to have smart behavior based on this.
376-
Intent statusIntent = new Intent();
377-
statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
378399
if (mPlugType != 0 && mLastPlugType == 0) {
379-
statusIntent.setAction(Intent.ACTION_POWER_CONNECTED);
380-
mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL);
400+
mHandler.post(new Runnable() {
401+
@Override
402+
public void run() {
403+
Intent statusIntent = new Intent(Intent.ACTION_POWER_CONNECTED);
404+
statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
405+
mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL);
406+
}
407+
});
381408
}
382409
else if (mPlugType == 0 && mLastPlugType != 0) {
383-
statusIntent.setAction(Intent.ACTION_POWER_DISCONNECTED);
384-
mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL);
410+
mHandler.post(new Runnable() {
411+
@Override
412+
public void run() {
413+
Intent statusIntent = new Intent(Intent.ACTION_POWER_DISCONNECTED);
414+
statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
415+
mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL);
416+
}
417+
});
385418
}
386419

387420
if (sendBatteryLow) {
388421
mSentLowBatteryBroadcast = true;
389-
statusIntent.setAction(Intent.ACTION_BATTERY_LOW);
390-
mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL);
422+
mHandler.post(new Runnable() {
423+
@Override
424+
public void run() {
425+
Intent statusIntent = new Intent(Intent.ACTION_BATTERY_LOW);
426+
statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
427+
mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL);
428+
}
429+
});
391430
} else if (mSentLowBatteryBroadcast && mLastBatteryLevel >= mLowBatteryCloseWarningLevel) {
392431
mSentLowBatteryBroadcast = false;
393-
statusIntent.setAction(Intent.ACTION_BATTERY_OKAY);
394-
mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL);
432+
mHandler.post(new Runnable() {
433+
@Override
434+
public void run() {
435+
Intent statusIntent = new Intent(Intent.ACTION_BATTERY_OKAY);
436+
statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
437+
mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL);
438+
}
439+
});
395440
}
396441

397442
// Update the battery LED
@@ -416,7 +461,7 @@ else if (mPlugType == 0 && mLastPlugType != 0) {
416461

417462
private void sendIntentLocked() {
418463
// Pack up the values and broadcast them to everyone
419-
Intent intent = new Intent(Intent.ACTION_BATTERY_CHANGED);
464+
final Intent intent = new Intent(Intent.ACTION_BATTERY_CHANGED);
420465
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
421466
| Intent.FLAG_RECEIVER_REPLACE_PENDING);
422467

@@ -446,7 +491,12 @@ private void sendIntentLocked() {
446491
", icon:" + icon + ", invalid charger:" + mInvalidCharger);
447492
}
448493

449-
ActivityManagerNative.broadcastStickyIntent(intent, null, UserHandle.USER_ALL);
494+
mHandler.post(new Runnable() {
495+
@Override
496+
public void run() {
497+
ActivityManagerNative.broadcastStickyIntent(intent, null, UserHandle.USER_ALL);
498+
}
499+
});
450500
}
451501

452502
private void logBatteryStatsLocked() {

0 commit comments

Comments
 (0)