5151public 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