Skip to content

Commit b820371

Browse files
author
Jeff Brown
committed
Add a thread to handle the radio shutdown.
Protect the ShutdownThread from possible hangs in the telephony, Bluetooth or NFC stack while turning off the radios. Bug: 6585958 Change-Id: I6b448c854c5a0efb0eedd90437853ef2571e785b
1 parent 80a1de1 commit b820371

File tree

1 file changed

+118
-87
lines changed

1 file changed

+118
-87
lines changed

services/java/com/android/server/pm/ShutdownThread.java

Lines changed: 118 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -51,11 +51,11 @@
5151
public final class ShutdownThread extends Thread {
5252
// constants
5353
private static final String TAG = "ShutdownThread";
54-
private static final int MAX_NUM_PHONE_STATE_READS = 24;
5554
private static final int PHONE_STATE_POLL_SLEEP_MSEC = 500;
5655
// maximum time we wait for the shutdown broadcast before going on.
5756
private static final int MAX_BROADCAST_TIME = 10*1000;
5857
private static final int MAX_SHUTDOWN_WAIT_TIME = 20*1000;
58+
private static final int MAX_RADIO_WAIT_TIME = 12*1000;
5959

6060
// length of vibration before shutting down
6161
private static final int SHUTDOWN_VIBRATE_MS = 500;
@@ -263,10 +263,6 @@ void actionDone() {
263263
* Shuts off power regardless of radio and bluetooth state if the alloted time has passed.
264264
*/
265265
public void run() {
266-
boolean nfcOff;
267-
boolean bluetoothOff;
268-
boolean radioOff;
269-
270266
BroadcastReceiver br = new BroadcastReceiver() {
271267
@Override public void onReceive(Context context, Intent intent) {
272268
// We don't allow apps to cancel this, so ignore the result.
@@ -324,89 +320,9 @@ public void run() {
324320
} catch (RemoteException e) {
325321
}
326322
}
327-
328-
final INfcAdapter nfc =
329-
INfcAdapter.Stub.asInterface(ServiceManager.checkService("nfc"));
330-
final ITelephony phone =
331-
ITelephony.Stub.asInterface(ServiceManager.checkService("phone"));
332-
final IBluetooth bluetooth =
333-
IBluetooth.Stub.asInterface(ServiceManager.checkService(
334-
BluetoothAdapter.BLUETOOTH_SERVICE));
335-
final IMountService mount =
336-
IMountService.Stub.asInterface(
337-
ServiceManager.checkService("mount"));
338-
339-
try {
340-
nfcOff = nfc == null ||
341-
nfc.getState() == NfcAdapter.STATE_OFF;
342-
if (!nfcOff) {
343-
Log.w(TAG, "Turning off NFC...");
344-
nfc.disable(false); // Don't persist new state
345-
}
346-
} catch (RemoteException ex) {
347-
Log.e(TAG, "RemoteException during NFC shutdown", ex);
348-
nfcOff = true;
349-
}
350-
351-
try {
352-
bluetoothOff = bluetooth == null ||
353-
bluetooth.getBluetoothState() == BluetoothAdapter.STATE_OFF;
354-
if (!bluetoothOff) {
355-
Log.w(TAG, "Disabling Bluetooth...");
356-
bluetooth.disable(false); // disable but don't persist new state
357-
}
358-
} catch (RemoteException ex) {
359-
Log.e(TAG, "RemoteException during bluetooth shutdown", ex);
360-
bluetoothOff = true;
361-
}
362-
363-
try {
364-
radioOff = phone == null || !phone.isRadioOn();
365-
if (!radioOff) {
366-
Log.w(TAG, "Turning off radio...");
367-
phone.setRadio(false);
368-
}
369-
} catch (RemoteException ex) {
370-
Log.e(TAG, "RemoteException during radio shutdown", ex);
371-
radioOff = true;
372-
}
373-
374-
Log.i(TAG, "Waiting for NFC, Bluetooth and Radio...");
375-
376-
// Wait a max of 32 seconds for clean shutdown
377-
for (int i = 0; i < MAX_NUM_PHONE_STATE_READS; i++) {
378-
if (!bluetoothOff) {
379-
try {
380-
bluetoothOff =
381-
bluetooth.getBluetoothState() == BluetoothAdapter.STATE_OFF;
382-
} catch (RemoteException ex) {
383-
Log.e(TAG, "RemoteException during bluetooth shutdown", ex);
384-
bluetoothOff = true;
385-
}
386-
}
387-
if (!radioOff) {
388-
try {
389-
radioOff = !phone.isRadioOn();
390-
} catch (RemoteException ex) {
391-
Log.e(TAG, "RemoteException during radio shutdown", ex);
392-
radioOff = true;
393-
}
394-
}
395-
if (!nfcOff) {
396-
try {
397-
nfcOff = nfc.getState() == NfcAdapter.STATE_OFF;
398-
} catch (RemoteException ex) {
399-
Log.e(TAG, "RemoteException during NFC shutdown", ex);
400-
nfcOff = true;
401-
}
402-
}
403323

404-
if (radioOff && bluetoothOff && nfcOff) {
405-
Log.i(TAG, "NFC, Radio and Bluetooth shutdown complete.");
406-
break;
407-
}
408-
SystemClock.sleep(PHONE_STATE_POLL_SLEEP_MSEC);
409-
}
324+
// Shutdown radios.
325+
shutdownRadios(MAX_RADIO_WAIT_TIME);
410326

411327
// Shutdown MountService to ensure media is in a safe state
412328
IMountShutdownObserver observer = new IMountShutdownObserver.Stub() {
@@ -417,11 +333,14 @@ public void onShutDownComplete(int statusCode) throws RemoteException {
417333
};
418334

419335
Log.i(TAG, "Shutting down MountService");
336+
420337
// Set initial variables and time out time.
421338
mActionDone = false;
422339
final long endShutTime = SystemClock.elapsedRealtime() + MAX_SHUTDOWN_WAIT_TIME;
423340
synchronized (mActionDoneSync) {
424341
try {
342+
final IMountService mount = IMountService.Stub.asInterface(
343+
ServiceManager.checkService("mount"));
425344
if (mount != null) {
426345
mount.shutdown(observer);
427346
} else {
@@ -446,6 +365,118 @@ public void onShutDownComplete(int statusCode) throws RemoteException {
446365
rebootOrShutdown(mReboot, mRebootReason);
447366
}
448367

368+
private void shutdownRadios(int timeout) {
369+
// If a radio is wedged, disabling it may hang so we do this work in another thread,
370+
// just in case.
371+
final long endTime = SystemClock.elapsedRealtime() + timeout;
372+
final boolean[] done = new boolean[1];
373+
Thread t = new Thread() {
374+
public void run() {
375+
boolean nfcOff;
376+
boolean bluetoothOff;
377+
boolean radioOff;
378+
379+
final INfcAdapter nfc =
380+
INfcAdapter.Stub.asInterface(ServiceManager.checkService("nfc"));
381+
final ITelephony phone =
382+
ITelephony.Stub.asInterface(ServiceManager.checkService("phone"));
383+
final IBluetooth bluetooth =
384+
IBluetooth.Stub.asInterface(ServiceManager.checkService(
385+
BluetoothAdapter.BLUETOOTH_SERVICE));
386+
387+
try {
388+
nfcOff = nfc == null ||
389+
nfc.getState() == NfcAdapter.STATE_OFF;
390+
if (!nfcOff) {
391+
Log.w(TAG, "Turning off NFC...");
392+
nfc.disable(false); // Don't persist new state
393+
}
394+
} catch (RemoteException ex) {
395+
Log.e(TAG, "RemoteException during NFC shutdown", ex);
396+
nfcOff = true;
397+
}
398+
399+
try {
400+
bluetoothOff = bluetooth == null ||
401+
bluetooth.getBluetoothState() == BluetoothAdapter.STATE_OFF;
402+
if (!bluetoothOff) {
403+
Log.w(TAG, "Disabling Bluetooth...");
404+
bluetooth.disable(false); // disable but don't persist new state
405+
}
406+
} catch (RemoteException ex) {
407+
Log.e(TAG, "RemoteException during bluetooth shutdown", ex);
408+
bluetoothOff = true;
409+
}
410+
411+
try {
412+
radioOff = phone == null || !phone.isRadioOn();
413+
if (!radioOff) {
414+
Log.w(TAG, "Turning off radio...");
415+
phone.setRadio(false);
416+
}
417+
} catch (RemoteException ex) {
418+
Log.e(TAG, "RemoteException during radio shutdown", ex);
419+
radioOff = true;
420+
}
421+
422+
Log.i(TAG, "Waiting for NFC, Bluetooth and Radio...");
423+
424+
while (SystemClock.elapsedRealtime() < endTime) {
425+
if (!bluetoothOff) {
426+
try {
427+
bluetoothOff =
428+
bluetooth.getBluetoothState() == BluetoothAdapter.STATE_OFF;
429+
} catch (RemoteException ex) {
430+
Log.e(TAG, "RemoteException during bluetooth shutdown", ex);
431+
bluetoothOff = true;
432+
}
433+
if (bluetoothOff) {
434+
Log.i(TAG, "Bluetooth turned off.");
435+
}
436+
}
437+
if (!radioOff) {
438+
try {
439+
radioOff = !phone.isRadioOn();
440+
} catch (RemoteException ex) {
441+
Log.e(TAG, "RemoteException during radio shutdown", ex);
442+
radioOff = true;
443+
}
444+
if (radioOff) {
445+
Log.i(TAG, "Radio turned off.");
446+
}
447+
}
448+
if (!nfcOff) {
449+
try {
450+
nfcOff = nfc.getState() == NfcAdapter.STATE_OFF;
451+
} catch (RemoteException ex) {
452+
Log.e(TAG, "RemoteException during NFC shutdown", ex);
453+
nfcOff = true;
454+
}
455+
if (radioOff) {
456+
Log.i(TAG, "NFC turned off.");
457+
}
458+
}
459+
460+
if (radioOff && bluetoothOff && nfcOff) {
461+
Log.i(TAG, "NFC, Radio and Bluetooth shutdown complete.");
462+
done[0] = true;
463+
break;
464+
}
465+
SystemClock.sleep(PHONE_STATE_POLL_SLEEP_MSEC);
466+
}
467+
}
468+
};
469+
470+
t.start();
471+
try {
472+
t.join(timeout);
473+
} catch (InterruptedException ex) {
474+
}
475+
if (!done[0]) {
476+
Log.w(TAG, "Timed out waiting for NFC, Radio and Bluetooth shutdown.");
477+
}
478+
}
479+
449480
/**
450481
* Do not call this directly. Use {@link #reboot(Context, String, boolean)}
451482
* or {@link #shutdown(Context, boolean)} instead.

0 commit comments

Comments
 (0)