blob: 69406c8f3bfb02ebfc410baa91c6051611e362e0 [file] [log] [blame]
Dianne Hackborn55280a92009-05-07 15:53:46 -07001/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17
Jeff Brown7304c342012-05-11 18:42:42 -070018package com.android.server.pm;
Dianne Hackborn55280a92009-05-07 15:53:46 -070019
20import android.app.ActivityManagerNative;
Joe Onoratod208e702010-10-08 16:22:43 -040021import android.app.AlertDialog;
22import android.app.Dialog;
Dianne Hackborn55280a92009-05-07 15:53:46 -070023import android.app.IActivityManager;
24import android.app.ProgressDialog;
Nick Pellybd022f42009-08-14 18:33:38 -070025import android.bluetooth.BluetoothAdapter;
26import android.bluetooth.IBluetooth;
Sunil Jogi3bba8d02012-04-10 13:12:26 -070027import android.nfc.NfcAdapter;
28import android.nfc.INfcAdapter;
Dianne Hackborn55280a92009-05-07 15:53:46 -070029import android.content.BroadcastReceiver;
30import android.content.Context;
31import android.content.DialogInterface;
32import android.content.Intent;
Joe Onoratod208e702010-10-08 16:22:43 -040033import android.content.IntentFilter;
Dianne Hackborn55280a92009-05-07 15:53:46 -070034import android.os.Handler;
Dianne Hackbornf99ae762010-03-08 12:43:51 -080035import android.os.PowerManager;
Dianne Hackborn55280a92009-05-07 15:53:46 -070036import android.os.RemoteException;
Dianne Hackborn55280a92009-05-07 15:53:46 -070037import android.os.ServiceManager;
38import android.os.SystemClock;
Kenny Rootf547d672010-09-22 10:36:48 -070039import android.os.SystemProperties;
Mike Lockwooda717f642010-04-01 20:01:44 -070040import android.os.Vibrator;
Jeff Brownc2346132012-04-13 01:55:38 -070041import android.os.SystemVibrator;
San Mehatb1043402010-02-05 08:26:50 -080042import android.os.storage.IMountService;
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -080043import android.os.storage.IMountShutdownObserver;
Dianne Hackborn568cae52009-10-07 16:13:39 -070044
Dianne Hackborn55280a92009-05-07 15:53:46 -070045import com.android.internal.telephony.ITelephony;
Jeff Brown7304c342012-05-11 18:42:42 -070046import com.android.server.PowerManagerService;
47
Dianne Hackborn55280a92009-05-07 15:53:46 -070048import android.util.Log;
49import android.view.WindowManager;
50
51public final class ShutdownThread extends Thread {
52 // constants
53 private static final String TAG = "ShutdownThread";
Dianne Hackborn55280a92009-05-07 15:53:46 -070054 private static final int PHONE_STATE_POLL_SLEEP_MSEC = 500;
55 // maximum time we wait for the shutdown broadcast before going on.
56 private static final int MAX_BROADCAST_TIME = 10*1000;
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -080057 private static final int MAX_SHUTDOWN_WAIT_TIME = 20*1000;
Jeff Brownb8203712012-05-31 17:39:13 -070058 private static final int MAX_RADIO_WAIT_TIME = 12*1000;
Mike Lockwooda717f642010-04-01 20:01:44 -070059
60 // length of vibration before shutting down
61 private static final int SHUTDOWN_VIBRATE_MS = 500;
Dianne Hackborn55280a92009-05-07 15:53:46 -070062
63 // state tracking
64 private static Object sIsStartedGuard = new Object();
65 private static boolean sIsStarted = false;
66
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -080067 private static boolean mReboot;
Dianne Hackborn19caadc2012-04-20 17:49:10 -070068 private static boolean mRebootSafeMode;
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -080069 private static String mRebootReason;
70
Kenny Rootf547d672010-09-22 10:36:48 -070071 // Provides shutdown assurance in case the system_server is killed
72 public static final String SHUTDOWN_ACTION_PROPERTY = "sys.shutdown.requested";
73
Dianne Hackborn19caadc2012-04-20 17:49:10 -070074 // Indicates whether we are rebooting into safe mode
75 public static final String REBOOT_SAFEMODE_PROPERTY = "persist.sys.safemode";
76
Dianne Hackborn55280a92009-05-07 15:53:46 -070077 // static instance of this thread
78 private static final ShutdownThread sInstance = new ShutdownThread();
79
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -080080 private final Object mActionDoneSync = new Object();
81 private boolean mActionDone;
Dianne Hackborn55280a92009-05-07 15:53:46 -070082 private Context mContext;
Dianne Hackbornf99ae762010-03-08 12:43:51 -080083 private PowerManager mPowerManager;
Mattias Larssoncd4e4272010-09-28 14:34:15 +020084 private PowerManager.WakeLock mCpuWakeLock;
85 private PowerManager.WakeLock mScreenWakeLock;
Dianne Hackborn55280a92009-05-07 15:53:46 -070086 private Handler mHandler;
87
88 private ShutdownThread() {
89 }
90
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -080091 /**
Dianne Hackborn55280a92009-05-07 15:53:46 -070092 * Request a clean shutdown, waiting for subsystems to clean up their
93 * state etc. Must be called from a Looper thread in which its UI
94 * is shown.
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -080095 *
Dianne Hackborn55280a92009-05-07 15:53:46 -070096 * @param context Context used to display the shutdown progress dialog.
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -080097 * @param confirm true if user confirmation is needed before shutting down.
Dianne Hackborn55280a92009-05-07 15:53:46 -070098 */
99 public static void shutdown(final Context context, boolean confirm) {
Dianne Hackborn19caadc2012-04-20 17:49:10 -0700100 mReboot = false;
101 mRebootSafeMode = false;
102 shutdownInner(context, confirm);
103 }
104
105 static void shutdownInner(final Context context, boolean confirm) {
Dianne Hackborn55280a92009-05-07 15:53:46 -0700106 // ensure that only one thread is trying to power down.
107 // any additional calls are just returned
Mike Lockwoodd67b2362010-07-26 07:18:21 -0400108 synchronized (sIsStartedGuard) {
Dianne Hackborn55280a92009-05-07 15:53:46 -0700109 if (sIsStarted) {
110 Log.d(TAG, "Request to shutdown already running, returning.");
111 return;
112 }
113 }
114
Joe Onoratod208e702010-10-08 16:22:43 -0400115 final int longPressBehavior = context.getResources().getInteger(
116 com.android.internal.R.integer.config_longPressOnPowerBehavior);
Dianne Hackborn19caadc2012-04-20 17:49:10 -0700117 final int resourceId = mRebootSafeMode
118 ? com.android.internal.R.string.reboot_safemode_confirm
119 : (longPressBehavior == 2
120 ? com.android.internal.R.string.shutdown_confirm_question
121 : com.android.internal.R.string.shutdown_confirm);
Joe Onoratod208e702010-10-08 16:22:43 -0400122
123 Log.d(TAG, "Notifying thread to start shutdown longPressBehavior=" + longPressBehavior);
Dianne Hackborn55280a92009-05-07 15:53:46 -0700124
125 if (confirm) {
Joe Onoratod208e702010-10-08 16:22:43 -0400126 final CloseDialogReceiver closer = new CloseDialogReceiver(context);
Dianne Hackborn55280a92009-05-07 15:53:46 -0700127 final AlertDialog dialog = new AlertDialog.Builder(context)
Dianne Hackborn19caadc2012-04-20 17:49:10 -0700128 .setTitle(mRebootSafeMode
129 ? com.android.internal.R.string.reboot_safemode_title
130 : com.android.internal.R.string.power_off)
Joe Onoratod208e702010-10-08 16:22:43 -0400131 .setMessage(resourceId)
Dianne Hackborn55280a92009-05-07 15:53:46 -0700132 .setPositiveButton(com.android.internal.R.string.yes, new DialogInterface.OnClickListener() {
133 public void onClick(DialogInterface dialog, int which) {
134 beginShutdownSequence(context);
135 }
136 })
137 .setNegativeButton(com.android.internal.R.string.no, null)
138 .create();
Joe Onoratod208e702010-10-08 16:22:43 -0400139 closer.dialog = dialog;
140 dialog.setOnDismissListener(closer);
Dianne Hackborn55280a92009-05-07 15:53:46 -0700141 dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
Dianne Hackborn55280a92009-05-07 15:53:46 -0700142 dialog.show();
143 } else {
144 beginShutdownSequence(context);
145 }
146 }
147
Joe Onoratod208e702010-10-08 16:22:43 -0400148 private static class CloseDialogReceiver extends BroadcastReceiver
149 implements DialogInterface.OnDismissListener {
150 private Context mContext;
151 public Dialog dialog;
152
153 CloseDialogReceiver(Context context) {
154 mContext = context;
155 IntentFilter filter = new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
156 context.registerReceiver(this, filter);
157 }
158
159 @Override
160 public void onReceive(Context context, Intent intent) {
161 dialog.cancel();
162 }
163
164 public void onDismiss(DialogInterface unused) {
165 mContext.unregisterReceiver(this);
166 }
167 }
168
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -0800169 /**
170 * Request a clean shutdown, waiting for subsystems to clean up their
171 * state etc. Must be called from a Looper thread in which its UI
172 * is shown.
173 *
174 * @param context Context used to display the shutdown progress dialog.
175 * @param reason code to pass to the kernel (e.g. "recovery"), or null.
176 * @param confirm true if user confirmation is needed before shutting down.
177 */
178 public static void reboot(final Context context, String reason, boolean confirm) {
179 mReboot = true;
Dianne Hackborn19caadc2012-04-20 17:49:10 -0700180 mRebootSafeMode = false;
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -0800181 mRebootReason = reason;
Dianne Hackborn19caadc2012-04-20 17:49:10 -0700182 shutdownInner(context, confirm);
183 }
184
185 /**
186 * Request a reboot into safe mode. Must be called from a Looper thread in which its UI
187 * is shown.
188 *
189 * @param context Context used to display the shutdown progress dialog.
190 * @param confirm true if user confirmation is needed before shutting down.
191 */
192 public static void rebootSafeMode(final Context context, boolean confirm) {
193 mReboot = true;
194 mRebootSafeMode = true;
195 mRebootReason = null;
196 shutdownInner(context, confirm);
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -0800197 }
198
Dianne Hackborn55280a92009-05-07 15:53:46 -0700199 private static void beginShutdownSequence(Context context) {
200 synchronized (sIsStartedGuard) {
Mike Lockwoodd67b2362010-07-26 07:18:21 -0400201 if (sIsStarted) {
Mathias Jeppsson8534a8e2010-08-17 13:33:09 +0200202 Log.d(TAG, "Shutdown sequence already running, returning.");
Mike Lockwoodd67b2362010-07-26 07:18:21 -0400203 return;
204 }
Dianne Hackborn55280a92009-05-07 15:53:46 -0700205 sIsStarted = true;
206 }
207
208 // throw up an indeterminate system dialog to indicate radio is
209 // shutting down.
210 ProgressDialog pd = new ProgressDialog(context);
211 pd.setTitle(context.getText(com.android.internal.R.string.power_off));
212 pd.setMessage(context.getText(com.android.internal.R.string.shutdown_progress));
213 pd.setIndeterminate(true);
214 pd.setCancelable(false);
215 pd.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
Dianne Hackborn55280a92009-05-07 15:53:46 -0700216
217 pd.show();
218
Dianne Hackborn55280a92009-05-07 15:53:46 -0700219 sInstance.mContext = context;
Dianne Hackbornf99ae762010-03-08 12:43:51 -0800220 sInstance.mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
Mattias Larssoncd4e4272010-09-28 14:34:15 +0200221
222 // make sure we never fall asleep again
223 sInstance.mCpuWakeLock = null;
224 try {
225 sInstance.mCpuWakeLock = sInstance.mPowerManager.newWakeLock(
226 PowerManager.PARTIAL_WAKE_LOCK, TAG + "-cpu");
227 sInstance.mCpuWakeLock.setReferenceCounted(false);
228 sInstance.mCpuWakeLock.acquire();
229 } catch (SecurityException e) {
230 Log.w(TAG, "No permission to acquire wake lock", e);
231 sInstance.mCpuWakeLock = null;
232 }
233
234 // also make sure the screen stays on for better user experience
235 sInstance.mScreenWakeLock = null;
Dianne Hackbornf99ae762010-03-08 12:43:51 -0800236 if (sInstance.mPowerManager.isScreenOn()) {
237 try {
Mattias Larssoncd4e4272010-09-28 14:34:15 +0200238 sInstance.mScreenWakeLock = sInstance.mPowerManager.newWakeLock(
239 PowerManager.FULL_WAKE_LOCK, TAG + "-screen");
240 sInstance.mScreenWakeLock.setReferenceCounted(false);
241 sInstance.mScreenWakeLock.acquire();
Dianne Hackbornf99ae762010-03-08 12:43:51 -0800242 } catch (SecurityException e) {
243 Log.w(TAG, "No permission to acquire wake lock", e);
Mattias Larssoncd4e4272010-09-28 14:34:15 +0200244 sInstance.mScreenWakeLock = null;
Dianne Hackbornf99ae762010-03-08 12:43:51 -0800245 }
246 }
Mattias Larssoncd4e4272010-09-28 14:34:15 +0200247
248 // start the thread that initiates shutdown
Dianne Hackborn55280a92009-05-07 15:53:46 -0700249 sInstance.mHandler = new Handler() {
250 };
251 sInstance.start();
252 }
253
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -0800254 void actionDone() {
255 synchronized (mActionDoneSync) {
256 mActionDone = true;
257 mActionDoneSync.notifyAll();
Dianne Hackborn55280a92009-05-07 15:53:46 -0700258 }
259 }
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -0800260
Dianne Hackborn55280a92009-05-07 15:53:46 -0700261 /**
262 * Makes sure we handle the shutdown gracefully.
263 * Shuts off power regardless of radio and bluetooth state if the alloted time has passed.
264 */
265 public void run() {
Dianne Hackborn55280a92009-05-07 15:53:46 -0700266 BroadcastReceiver br = new BroadcastReceiver() {
267 @Override public void onReceive(Context context, Intent intent) {
268 // We don't allow apps to cancel this, so ignore the result.
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -0800269 actionDone();
Dianne Hackborn55280a92009-05-07 15:53:46 -0700270 }
271 };
Kenny Rootf547d672010-09-22 10:36:48 -0700272
273 /*
274 * Write a system property in case the system_server reboots before we
275 * get to the actual hardware restart. If that happens, we'll retry at
276 * the beginning of the SystemServer startup.
277 */
278 {
279 String reason = (mReboot ? "1" : "0") + (mRebootReason != null ? mRebootReason : "");
280 SystemProperties.set(SHUTDOWN_ACTION_PROPERTY, reason);
281 }
282
Dianne Hackborn19caadc2012-04-20 17:49:10 -0700283 /*
284 * If we are rebooting into safe mode, write a system property
285 * indicating so.
286 */
287 if (mRebootSafeMode) {
288 SystemProperties.set(REBOOT_SAFEMODE_PROPERTY, "1");
289 }
290
Dianne Hackborn55280a92009-05-07 15:53:46 -0700291 Log.i(TAG, "Sending shutdown broadcast...");
292
293 // First send the high-level shut down broadcast.
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -0800294 mActionDone = false;
Dianne Hackborn55280a92009-05-07 15:53:46 -0700295 mContext.sendOrderedBroadcast(new Intent(Intent.ACTION_SHUTDOWN), null,
296 br, mHandler, 0, null, null);
297
Mike Lockwood098e58d2010-05-13 16:29:49 -0400298 final long endTime = SystemClock.elapsedRealtime() + MAX_BROADCAST_TIME;
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -0800299 synchronized (mActionDoneSync) {
300 while (!mActionDone) {
Mike Lockwood098e58d2010-05-13 16:29:49 -0400301 long delay = endTime - SystemClock.elapsedRealtime();
Dianne Hackborn55280a92009-05-07 15:53:46 -0700302 if (delay <= 0) {
303 Log.w(TAG, "Shutdown broadcast timed out");
304 break;
305 }
306 try {
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -0800307 mActionDoneSync.wait(delay);
Dianne Hackborn55280a92009-05-07 15:53:46 -0700308 } catch (InterruptedException e) {
309 }
310 }
311 }
312
313 Log.i(TAG, "Shutting down activity manager...");
314
315 final IActivityManager am =
316 ActivityManagerNative.asInterface(ServiceManager.checkService("activity"));
317 if (am != null) {
318 try {
319 am.shutdown(MAX_BROADCAST_TIME);
320 } catch (RemoteException e) {
321 }
322 }
Sunil Jogi3bba8d02012-04-10 13:12:26 -0700323
Jeff Brownb8203712012-05-31 17:39:13 -0700324 // Shutdown radios.
325 shutdownRadios(MAX_RADIO_WAIT_TIME);
Dianne Hackborn55280a92009-05-07 15:53:46 -0700326
San Mehat9f7f7ca2010-01-07 11:34:59 -0800327 // Shutdown MountService to ensure media is in a safe state
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -0800328 IMountShutdownObserver observer = new IMountShutdownObserver.Stub() {
329 public void onShutDownComplete(int statusCode) throws RemoteException {
330 Log.w(TAG, "Result code " + statusCode + " from MountService.shutdown");
331 actionDone();
San Mehat9f7f7ca2010-01-07 11:34:59 -0800332 }
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -0800333 };
334
335 Log.i(TAG, "Shutting down MountService");
Jeff Brownb8203712012-05-31 17:39:13 -0700336
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -0800337 // Set initial variables and time out time.
338 mActionDone = false;
Mike Lockwood098e58d2010-05-13 16:29:49 -0400339 final long endShutTime = SystemClock.elapsedRealtime() + MAX_SHUTDOWN_WAIT_TIME;
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -0800340 synchronized (mActionDoneSync) {
341 try {
Jeff Brownb8203712012-05-31 17:39:13 -0700342 final IMountService mount = IMountService.Stub.asInterface(
343 ServiceManager.checkService("mount"));
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -0800344 if (mount != null) {
345 mount.shutdown(observer);
346 } else {
347 Log.w(TAG, "MountService unavailable for shutdown");
348 }
349 } catch (Exception e) {
350 Log.e(TAG, "Exception during MountService shutdown", e);
351 }
352 while (!mActionDone) {
Mike Lockwood098e58d2010-05-13 16:29:49 -0400353 long delay = endShutTime - SystemClock.elapsedRealtime();
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -0800354 if (delay <= 0) {
355 Log.w(TAG, "Shutdown wait timed out");
356 break;
357 }
358 try {
359 mActionDoneSync.wait(delay);
360 } catch (InterruptedException e) {
361 }
362 }
San Mehat9f7f7ca2010-01-07 11:34:59 -0800363 }
364
Kenny Rootf547d672010-09-22 10:36:48 -0700365 rebootOrShutdown(mReboot, mRebootReason);
366 }
367
Jeff Brownb8203712012-05-31 17:39:13 -0700368 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
Kenny Rootf547d672010-09-22 10:36:48 -0700480 /**
481 * Do not call this directly. Use {@link #reboot(Context, String, boolean)}
482 * or {@link #shutdown(Context, boolean)} instead.
483 *
484 * @param reboot true to reboot or false to shutdown
485 * @param reason reason for reboot
486 */
487 public static void rebootOrShutdown(boolean reboot, String reason) {
488 if (reboot) {
489 Log.i(TAG, "Rebooting, reason: " + reason);
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -0800490 try {
Jeff Brown7304c342012-05-11 18:42:42 -0700491 PowerManagerService.lowLevelReboot(reason);
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -0800492 } catch (Exception e) {
493 Log.e(TAG, "Reboot failed, will attempt shutdown instead", e);
494 }
Mike Lockwooda717f642010-04-01 20:01:44 -0700495 } else if (SHUTDOWN_VIBRATE_MS > 0) {
496 // vibrate before shutting down
Jeff Brownc2346132012-04-13 01:55:38 -0700497 Vibrator vibrator = new SystemVibrator();
Brad Fitzpatrick26e9cf32010-10-19 09:33:09 -0700498 try {
499 vibrator.vibrate(SHUTDOWN_VIBRATE_MS);
500 } catch (Exception e) {
501 // Failure to vibrate shouldn't interrupt shutdown. Just log it.
502 Log.w(TAG, "Failed to vibrate during shutdown.", e);
503 }
504
Mike Lockwooda717f642010-04-01 20:01:44 -0700505 // vibrator is asynchronous so we need to wait to avoid shutting down too soon.
506 try {
507 Thread.sleep(SHUTDOWN_VIBRATE_MS);
Brad Fitzpatricke3316442010-10-14 19:40:56 -0700508 } catch (InterruptedException unused) {
Mike Lockwooda717f642010-04-01 20:01:44 -0700509 }
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -0800510 }
511
512 // Shutdown power
Dianne Hackborn55280a92009-05-07 15:53:46 -0700513 Log.i(TAG, "Performing low-level shutdown...");
Jeff Brown7304c342012-05-11 18:42:42 -0700514 PowerManagerService.lowLevelShutdown();
Dianne Hackborn55280a92009-05-07 15:53:46 -0700515 }
516}