blob: d867ff9eed03734485d7765a423e1e7bc7534875 [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
18package com.android.internal.app;
19
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;
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -080035import android.os.Power;
Dianne Hackbornf99ae762010-03-08 12:43:51 -080036import android.os.PowerManager;
Dianne Hackborn55280a92009-05-07 15:53:46 -070037import android.os.RemoteException;
Dianne Hackborn55280a92009-05-07 15:53:46 -070038import android.os.ServiceManager;
39import android.os.SystemClock;
Kenny Rootf547d672010-09-22 10:36:48 -070040import android.os.SystemProperties;
Mike Lockwooda717f642010-04-01 20:01:44 -070041import android.os.Vibrator;
Jeff Brownc2346132012-04-13 01:55:38 -070042import android.os.SystemVibrator;
San Mehatb1043402010-02-05 08:26:50 -080043import android.os.storage.IMountService;
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -080044import android.os.storage.IMountShutdownObserver;
Dianne Hackborn568cae52009-10-07 16:13:39 -070045
Dianne Hackborn55280a92009-05-07 15:53:46 -070046import com.android.internal.telephony.ITelephony;
47import android.util.Log;
48import android.view.WindowManager;
49
50public final class ShutdownThread extends Thread {
51 // constants
52 private static final String TAG = "ShutdownThread";
Sunil Jogi3bba8d02012-04-10 13:12:26 -070053 private static final int MAX_NUM_PHONE_STATE_READS = 24;
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;
Mike Lockwooda717f642010-04-01 20:01:44 -070058
59 // length of vibration before shutting down
60 private static final int SHUTDOWN_VIBRATE_MS = 500;
Dianne Hackborn55280a92009-05-07 15:53:46 -070061
62 // state tracking
63 private static Object sIsStartedGuard = new Object();
64 private static boolean sIsStarted = false;
65
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -080066 private static boolean mReboot;
Dianne Hackborn19caadc2012-04-20 17:49:10 -070067 private static boolean mRebootSafeMode;
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -080068 private static String mRebootReason;
69
Kenny Rootf547d672010-09-22 10:36:48 -070070 // Provides shutdown assurance in case the system_server is killed
71 public static final String SHUTDOWN_ACTION_PROPERTY = "sys.shutdown.requested";
72
Dianne Hackborn19caadc2012-04-20 17:49:10 -070073 // Indicates whether we are rebooting into safe mode
74 public static final String REBOOT_SAFEMODE_PROPERTY = "persist.sys.safemode";
75
Dianne Hackborn55280a92009-05-07 15:53:46 -070076 // static instance of this thread
77 private static final ShutdownThread sInstance = new ShutdownThread();
78
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -080079 private final Object mActionDoneSync = new Object();
80 private boolean mActionDone;
Dianne Hackborn55280a92009-05-07 15:53:46 -070081 private Context mContext;
Dianne Hackbornf99ae762010-03-08 12:43:51 -080082 private PowerManager mPowerManager;
Mattias Larssoncd4e4272010-09-28 14:34:15 +020083 private PowerManager.WakeLock mCpuWakeLock;
84 private PowerManager.WakeLock mScreenWakeLock;
Dianne Hackborn55280a92009-05-07 15:53:46 -070085 private Handler mHandler;
86
87 private ShutdownThread() {
88 }
89
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -080090 /**
Dianne Hackborn55280a92009-05-07 15:53:46 -070091 * Request a clean shutdown, waiting for subsystems to clean up their
92 * state etc. Must be called from a Looper thread in which its UI
93 * is shown.
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -080094 *
Dianne Hackborn55280a92009-05-07 15:53:46 -070095 * @param context Context used to display the shutdown progress dialog.
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -080096 * @param confirm true if user confirmation is needed before shutting down.
Dianne Hackborn55280a92009-05-07 15:53:46 -070097 */
98 public static void shutdown(final Context context, boolean confirm) {
Dianne Hackborn19caadc2012-04-20 17:49:10 -070099 mReboot = false;
100 mRebootSafeMode = false;
101 shutdownInner(context, confirm);
102 }
103
104 static void shutdownInner(final Context context, boolean confirm) {
Dianne Hackborn55280a92009-05-07 15:53:46 -0700105 // ensure that only one thread is trying to power down.
106 // any additional calls are just returned
Mike Lockwoodd67b2362010-07-26 07:18:21 -0400107 synchronized (sIsStartedGuard) {
Dianne Hackborn55280a92009-05-07 15:53:46 -0700108 if (sIsStarted) {
109 Log.d(TAG, "Request to shutdown already running, returning.");
110 return;
111 }
112 }
113
Joe Onoratod208e702010-10-08 16:22:43 -0400114 final int longPressBehavior = context.getResources().getInteger(
115 com.android.internal.R.integer.config_longPressOnPowerBehavior);
Dianne Hackborn19caadc2012-04-20 17:49:10 -0700116 final int resourceId = mRebootSafeMode
117 ? com.android.internal.R.string.reboot_safemode_confirm
118 : (longPressBehavior == 2
119 ? com.android.internal.R.string.shutdown_confirm_question
120 : com.android.internal.R.string.shutdown_confirm);
Joe Onoratod208e702010-10-08 16:22:43 -0400121
122 Log.d(TAG, "Notifying thread to start shutdown longPressBehavior=" + longPressBehavior);
Dianne Hackborn55280a92009-05-07 15:53:46 -0700123
124 if (confirm) {
Joe Onoratod208e702010-10-08 16:22:43 -0400125 final CloseDialogReceiver closer = new CloseDialogReceiver(context);
Dianne Hackborn55280a92009-05-07 15:53:46 -0700126 final AlertDialog dialog = new AlertDialog.Builder(context)
Dianne Hackborn19caadc2012-04-20 17:49:10 -0700127 .setTitle(mRebootSafeMode
128 ? com.android.internal.R.string.reboot_safemode_title
129 : com.android.internal.R.string.power_off)
Joe Onoratod208e702010-10-08 16:22:43 -0400130 .setMessage(resourceId)
Dianne Hackborn55280a92009-05-07 15:53:46 -0700131 .setPositiveButton(com.android.internal.R.string.yes, new DialogInterface.OnClickListener() {
132 public void onClick(DialogInterface dialog, int which) {
133 beginShutdownSequence(context);
134 }
135 })
136 .setNegativeButton(com.android.internal.R.string.no, null)
137 .create();
Joe Onoratod208e702010-10-08 16:22:43 -0400138 closer.dialog = dialog;
139 dialog.setOnDismissListener(closer);
Dianne Hackborn55280a92009-05-07 15:53:46 -0700140 dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
Dianne Hackborn55280a92009-05-07 15:53:46 -0700141 dialog.show();
142 } else {
143 beginShutdownSequence(context);
144 }
145 }
146
Joe Onoratod208e702010-10-08 16:22:43 -0400147 private static class CloseDialogReceiver extends BroadcastReceiver
148 implements DialogInterface.OnDismissListener {
149 private Context mContext;
150 public Dialog dialog;
151
152 CloseDialogReceiver(Context context) {
153 mContext = context;
154 IntentFilter filter = new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
155 context.registerReceiver(this, filter);
156 }
157
158 @Override
159 public void onReceive(Context context, Intent intent) {
160 dialog.cancel();
161 }
162
163 public void onDismiss(DialogInterface unused) {
164 mContext.unregisterReceiver(this);
165 }
166 }
167
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -0800168 /**
169 * Request a clean shutdown, waiting for subsystems to clean up their
170 * state etc. Must be called from a Looper thread in which its UI
171 * is shown.
172 *
173 * @param context Context used to display the shutdown progress dialog.
174 * @param reason code to pass to the kernel (e.g. "recovery"), or null.
175 * @param confirm true if user confirmation is needed before shutting down.
176 */
177 public static void reboot(final Context context, String reason, boolean confirm) {
178 mReboot = true;
Dianne Hackborn19caadc2012-04-20 17:49:10 -0700179 mRebootSafeMode = false;
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -0800180 mRebootReason = reason;
Dianne Hackborn19caadc2012-04-20 17:49:10 -0700181 shutdownInner(context, confirm);
182 }
183
184 /**
185 * Request a reboot into safe mode. Must be called from a Looper thread in which its UI
186 * is shown.
187 *
188 * @param context Context used to display the shutdown progress dialog.
189 * @param confirm true if user confirmation is needed before shutting down.
190 */
191 public static void rebootSafeMode(final Context context, boolean confirm) {
192 mReboot = true;
193 mRebootSafeMode = true;
194 mRebootReason = null;
195 shutdownInner(context, confirm);
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -0800196 }
197
Dianne Hackborn55280a92009-05-07 15:53:46 -0700198 private static void beginShutdownSequence(Context context) {
199 synchronized (sIsStartedGuard) {
Mike Lockwoodd67b2362010-07-26 07:18:21 -0400200 if (sIsStarted) {
Mathias Jeppsson8534a8e2010-08-17 13:33:09 +0200201 Log.d(TAG, "Shutdown sequence already running, returning.");
Mike Lockwoodd67b2362010-07-26 07:18:21 -0400202 return;
203 }
Dianne Hackborn55280a92009-05-07 15:53:46 -0700204 sIsStarted = true;
205 }
206
207 // throw up an indeterminate system dialog to indicate radio is
208 // shutting down.
209 ProgressDialog pd = new ProgressDialog(context);
210 pd.setTitle(context.getText(com.android.internal.R.string.power_off));
211 pd.setMessage(context.getText(com.android.internal.R.string.shutdown_progress));
212 pd.setIndeterminate(true);
213 pd.setCancelable(false);
214 pd.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
Dianne Hackborn55280a92009-05-07 15:53:46 -0700215
216 pd.show();
217
Dianne Hackborn55280a92009-05-07 15:53:46 -0700218 sInstance.mContext = context;
Dianne Hackbornf99ae762010-03-08 12:43:51 -0800219 sInstance.mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
Mattias Larssoncd4e4272010-09-28 14:34:15 +0200220
221 // make sure we never fall asleep again
222 sInstance.mCpuWakeLock = null;
223 try {
224 sInstance.mCpuWakeLock = sInstance.mPowerManager.newWakeLock(
225 PowerManager.PARTIAL_WAKE_LOCK, TAG + "-cpu");
226 sInstance.mCpuWakeLock.setReferenceCounted(false);
227 sInstance.mCpuWakeLock.acquire();
228 } catch (SecurityException e) {
229 Log.w(TAG, "No permission to acquire wake lock", e);
230 sInstance.mCpuWakeLock = null;
231 }
232
233 // also make sure the screen stays on for better user experience
234 sInstance.mScreenWakeLock = null;
Dianne Hackbornf99ae762010-03-08 12:43:51 -0800235 if (sInstance.mPowerManager.isScreenOn()) {
236 try {
Mattias Larssoncd4e4272010-09-28 14:34:15 +0200237 sInstance.mScreenWakeLock = sInstance.mPowerManager.newWakeLock(
238 PowerManager.FULL_WAKE_LOCK, TAG + "-screen");
239 sInstance.mScreenWakeLock.setReferenceCounted(false);
240 sInstance.mScreenWakeLock.acquire();
Dianne Hackbornf99ae762010-03-08 12:43:51 -0800241 } catch (SecurityException e) {
242 Log.w(TAG, "No permission to acquire wake lock", e);
Mattias Larssoncd4e4272010-09-28 14:34:15 +0200243 sInstance.mScreenWakeLock = null;
Dianne Hackbornf99ae762010-03-08 12:43:51 -0800244 }
245 }
Mattias Larssoncd4e4272010-09-28 14:34:15 +0200246
247 // start the thread that initiates shutdown
Dianne Hackborn55280a92009-05-07 15:53:46 -0700248 sInstance.mHandler = new Handler() {
249 };
250 sInstance.start();
251 }
252
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -0800253 void actionDone() {
254 synchronized (mActionDoneSync) {
255 mActionDone = true;
256 mActionDoneSync.notifyAll();
Dianne Hackborn55280a92009-05-07 15:53:46 -0700257 }
258 }
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -0800259
Dianne Hackborn55280a92009-05-07 15:53:46 -0700260 /**
261 * Makes sure we handle the shutdown gracefully.
262 * Shuts off power regardless of radio and bluetooth state if the alloted time has passed.
263 */
264 public void run() {
Sunil Jogi3bba8d02012-04-10 13:12:26 -0700265 boolean nfcOff;
Dianne Hackborn55280a92009-05-07 15:53:46 -0700266 boolean bluetoothOff;
267 boolean radioOff;
268
269 BroadcastReceiver br = new BroadcastReceiver() {
270 @Override public void onReceive(Context context, Intent intent) {
271 // We don't allow apps to cancel this, so ignore the result.
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -0800272 actionDone();
Dianne Hackborn55280a92009-05-07 15:53:46 -0700273 }
274 };
Kenny Rootf547d672010-09-22 10:36:48 -0700275
276 /*
277 * Write a system property in case the system_server reboots before we
278 * get to the actual hardware restart. If that happens, we'll retry at
279 * the beginning of the SystemServer startup.
280 */
281 {
282 String reason = (mReboot ? "1" : "0") + (mRebootReason != null ? mRebootReason : "");
283 SystemProperties.set(SHUTDOWN_ACTION_PROPERTY, reason);
284 }
285
Dianne Hackborn19caadc2012-04-20 17:49:10 -0700286 /*
287 * If we are rebooting into safe mode, write a system property
288 * indicating so.
289 */
290 if (mRebootSafeMode) {
291 SystemProperties.set(REBOOT_SAFEMODE_PROPERTY, "1");
292 }
293
Dianne Hackborn55280a92009-05-07 15:53:46 -0700294 Log.i(TAG, "Sending shutdown broadcast...");
295
296 // First send the high-level shut down broadcast.
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -0800297 mActionDone = false;
Dianne Hackborn55280a92009-05-07 15:53:46 -0700298 mContext.sendOrderedBroadcast(new Intent(Intent.ACTION_SHUTDOWN), null,
299 br, mHandler, 0, null, null);
300
Mike Lockwood098e58d2010-05-13 16:29:49 -0400301 final long endTime = SystemClock.elapsedRealtime() + MAX_BROADCAST_TIME;
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -0800302 synchronized (mActionDoneSync) {
303 while (!mActionDone) {
Mike Lockwood098e58d2010-05-13 16:29:49 -0400304 long delay = endTime - SystemClock.elapsedRealtime();
Dianne Hackborn55280a92009-05-07 15:53:46 -0700305 if (delay <= 0) {
306 Log.w(TAG, "Shutdown broadcast timed out");
307 break;
308 }
309 try {
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -0800310 mActionDoneSync.wait(delay);
Dianne Hackborn55280a92009-05-07 15:53:46 -0700311 } catch (InterruptedException e) {
312 }
313 }
314 }
315
316 Log.i(TAG, "Shutting down activity manager...");
317
318 final IActivityManager am =
319 ActivityManagerNative.asInterface(ServiceManager.checkService("activity"));
320 if (am != null) {
321 try {
322 am.shutdown(MAX_BROADCAST_TIME);
323 } catch (RemoteException e) {
324 }
325 }
326
Sunil Jogi3bba8d02012-04-10 13:12:26 -0700327 final INfcAdapter nfc =
328 INfcAdapter.Stub.asInterface(ServiceManager.checkService("nfc"));
Dianne Hackborn55280a92009-05-07 15:53:46 -0700329 final ITelephony phone =
330 ITelephony.Stub.asInterface(ServiceManager.checkService("phone"));
Nick Pellybd022f42009-08-14 18:33:38 -0700331 final IBluetooth bluetooth =
332 IBluetooth.Stub.asInterface(ServiceManager.checkService(
Nick Pellyf242b7b2009-10-08 00:12:45 +0200333 BluetoothAdapter.BLUETOOTH_SERVICE));
San Mehat9f7f7ca2010-01-07 11:34:59 -0800334 final IMountService mount =
335 IMountService.Stub.asInterface(
336 ServiceManager.checkService("mount"));
Sunil Jogi3bba8d02012-04-10 13:12:26 -0700337
338 try {
339 nfcOff = nfc == null ||
340 nfc.getState() == NfcAdapter.STATE_OFF;
341 if (!nfcOff) {
342 Log.w(TAG, "Turning off NFC...");
343 nfc.disable(false); // Don't persist new state
344 }
345 } catch (RemoteException ex) {
346 Log.e(TAG, "RemoteException during NFC shutdown", ex);
347 nfcOff = true;
348 }
349
Dianne Hackborn55280a92009-05-07 15:53:46 -0700350 try {
351 bluetoothOff = bluetooth == null ||
Nick Pellyde893f52009-09-08 13:15:33 -0700352 bluetooth.getBluetoothState() == BluetoothAdapter.STATE_OFF;
Dianne Hackborn55280a92009-05-07 15:53:46 -0700353 if (!bluetoothOff) {
354 Log.w(TAG, "Disabling Bluetooth...");
355 bluetooth.disable(false); // disable but don't persist new state
356 }
357 } catch (RemoteException ex) {
358 Log.e(TAG, "RemoteException during bluetooth shutdown", ex);
359 bluetoothOff = true;
360 }
361
362 try {
363 radioOff = phone == null || !phone.isRadioOn();
364 if (!radioOff) {
365 Log.w(TAG, "Turning off radio...");
366 phone.setRadio(false);
367 }
368 } catch (RemoteException ex) {
369 Log.e(TAG, "RemoteException during radio shutdown", ex);
370 radioOff = true;
371 }
372
Sunil Jogi3bba8d02012-04-10 13:12:26 -0700373 Log.i(TAG, "Waiting for NFC, Bluetooth and Radio...");
Dianne Hackborn55280a92009-05-07 15:53:46 -0700374
375 // Wait a max of 32 seconds for clean shutdown
376 for (int i = 0; i < MAX_NUM_PHONE_STATE_READS; i++) {
377 if (!bluetoothOff) {
378 try {
379 bluetoothOff =
Nick Pellyde893f52009-09-08 13:15:33 -0700380 bluetooth.getBluetoothState() == BluetoothAdapter.STATE_OFF;
Dianne Hackborn55280a92009-05-07 15:53:46 -0700381 } catch (RemoteException ex) {
382 Log.e(TAG, "RemoteException during bluetooth shutdown", ex);
383 bluetoothOff = true;
384 }
385 }
386 if (!radioOff) {
387 try {
388 radioOff = !phone.isRadioOn();
389 } catch (RemoteException ex) {
390 Log.e(TAG, "RemoteException during radio shutdown", ex);
391 radioOff = true;
392 }
393 }
Sunil Jogi3bba8d02012-04-10 13:12:26 -0700394 if (!nfcOff) {
395 try {
396 nfcOff = nfc.getState() == NfcAdapter.STATE_OFF;
397 } catch (RemoteException ex) {
398 Log.e(TAG, "RemoteException during NFC shutdown", ex);
399 nfcOff = true;
400 }
401 }
402
403 if (radioOff && bluetoothOff && nfcOff) {
404 Log.i(TAG, "NFC, Radio and Bluetooth shutdown complete.");
Dianne Hackborn55280a92009-05-07 15:53:46 -0700405 break;
406 }
407 SystemClock.sleep(PHONE_STATE_POLL_SLEEP_MSEC);
408 }
409
San Mehat9f7f7ca2010-01-07 11:34:59 -0800410 // Shutdown MountService to ensure media is in a safe state
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -0800411 IMountShutdownObserver observer = new IMountShutdownObserver.Stub() {
412 public void onShutDownComplete(int statusCode) throws RemoteException {
413 Log.w(TAG, "Result code " + statusCode + " from MountService.shutdown");
414 actionDone();
San Mehat9f7f7ca2010-01-07 11:34:59 -0800415 }
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -0800416 };
417
418 Log.i(TAG, "Shutting down MountService");
419 // Set initial variables and time out time.
420 mActionDone = false;
Mike Lockwood098e58d2010-05-13 16:29:49 -0400421 final long endShutTime = SystemClock.elapsedRealtime() + MAX_SHUTDOWN_WAIT_TIME;
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -0800422 synchronized (mActionDoneSync) {
423 try {
424 if (mount != null) {
425 mount.shutdown(observer);
426 } else {
427 Log.w(TAG, "MountService unavailable for shutdown");
428 }
429 } catch (Exception e) {
430 Log.e(TAG, "Exception during MountService shutdown", e);
431 }
432 while (!mActionDone) {
Mike Lockwood098e58d2010-05-13 16:29:49 -0400433 long delay = endShutTime - SystemClock.elapsedRealtime();
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -0800434 if (delay <= 0) {
435 Log.w(TAG, "Shutdown wait timed out");
436 break;
437 }
438 try {
439 mActionDoneSync.wait(delay);
440 } catch (InterruptedException e) {
441 }
442 }
San Mehat9f7f7ca2010-01-07 11:34:59 -0800443 }
444
Kenny Rootf547d672010-09-22 10:36:48 -0700445 rebootOrShutdown(mReboot, mRebootReason);
446 }
447
448 /**
449 * Do not call this directly. Use {@link #reboot(Context, String, boolean)}
450 * or {@link #shutdown(Context, boolean)} instead.
451 *
452 * @param reboot true to reboot or false to shutdown
453 * @param reason reason for reboot
454 */
455 public static void rebootOrShutdown(boolean reboot, String reason) {
456 if (reboot) {
457 Log.i(TAG, "Rebooting, reason: " + reason);
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -0800458 try {
Kenny Rootf547d672010-09-22 10:36:48 -0700459 Power.reboot(reason);
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -0800460 } catch (Exception e) {
461 Log.e(TAG, "Reboot failed, will attempt shutdown instead", e);
462 }
Mike Lockwooda717f642010-04-01 20:01:44 -0700463 } else if (SHUTDOWN_VIBRATE_MS > 0) {
464 // vibrate before shutting down
Jeff Brownc2346132012-04-13 01:55:38 -0700465 Vibrator vibrator = new SystemVibrator();
Brad Fitzpatrick26e9cf32010-10-19 09:33:09 -0700466 try {
467 vibrator.vibrate(SHUTDOWN_VIBRATE_MS);
468 } catch (Exception e) {
469 // Failure to vibrate shouldn't interrupt shutdown. Just log it.
470 Log.w(TAG, "Failed to vibrate during shutdown.", e);
471 }
472
Mike Lockwooda717f642010-04-01 20:01:44 -0700473 // vibrator is asynchronous so we need to wait to avoid shutting down too soon.
474 try {
475 Thread.sleep(SHUTDOWN_VIBRATE_MS);
Brad Fitzpatricke3316442010-10-14 19:40:56 -0700476 } catch (InterruptedException unused) {
Mike Lockwooda717f642010-04-01 20:01:44 -0700477 }
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -0800478 }
479
480 // Shutdown power
Dianne Hackborn55280a92009-05-07 15:53:46 -0700481 Log.i(TAG, "Performing low-level shutdown...");
482 Power.shutdown();
483 }
484}