blob: 1d6e068184de8f5f79f41f0114cc4df24e792c2c [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";
Sunil Jogi3bba8d02012-04-10 13:12:26 -070054 private static final int MAX_NUM_PHONE_STATE_READS = 24;
Dianne Hackborn55280a92009-05-07 15:53:46 -070055 private static final int PHONE_STATE_POLL_SLEEP_MSEC = 500;
56 // maximum time we wait for the shutdown broadcast before going on.
57 private static final int MAX_BROADCAST_TIME = 10*1000;
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -080058 private static final int MAX_SHUTDOWN_WAIT_TIME = 20*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() {
Sunil Jogi3bba8d02012-04-10 13:12:26 -0700266 boolean nfcOff;
Dianne Hackborn55280a92009-05-07 15:53:46 -0700267 boolean bluetoothOff;
268 boolean radioOff;
269
270 BroadcastReceiver br = new BroadcastReceiver() {
271 @Override public void onReceive(Context context, Intent intent) {
272 // We don't allow apps to cancel this, so ignore the result.
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -0800273 actionDone();
Dianne Hackborn55280a92009-05-07 15:53:46 -0700274 }
275 };
Kenny Rootf547d672010-09-22 10:36:48 -0700276
277 /*
278 * Write a system property in case the system_server reboots before we
279 * get to the actual hardware restart. If that happens, we'll retry at
280 * the beginning of the SystemServer startup.
281 */
282 {
283 String reason = (mReboot ? "1" : "0") + (mRebootReason != null ? mRebootReason : "");
284 SystemProperties.set(SHUTDOWN_ACTION_PROPERTY, reason);
285 }
286
Dianne Hackborn19caadc2012-04-20 17:49:10 -0700287 /*
288 * If we are rebooting into safe mode, write a system property
289 * indicating so.
290 */
291 if (mRebootSafeMode) {
292 SystemProperties.set(REBOOT_SAFEMODE_PROPERTY, "1");
293 }
294
Dianne Hackborn55280a92009-05-07 15:53:46 -0700295 Log.i(TAG, "Sending shutdown broadcast...");
296
297 // First send the high-level shut down broadcast.
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -0800298 mActionDone = false;
Dianne Hackborn55280a92009-05-07 15:53:46 -0700299 mContext.sendOrderedBroadcast(new Intent(Intent.ACTION_SHUTDOWN), null,
300 br, mHandler, 0, null, null);
301
Mike Lockwood098e58d2010-05-13 16:29:49 -0400302 final long endTime = SystemClock.elapsedRealtime() + MAX_BROADCAST_TIME;
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -0800303 synchronized (mActionDoneSync) {
304 while (!mActionDone) {
Mike Lockwood098e58d2010-05-13 16:29:49 -0400305 long delay = endTime - SystemClock.elapsedRealtime();
Dianne Hackborn55280a92009-05-07 15:53:46 -0700306 if (delay <= 0) {
307 Log.w(TAG, "Shutdown broadcast timed out");
308 break;
309 }
310 try {
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -0800311 mActionDoneSync.wait(delay);
Dianne Hackborn55280a92009-05-07 15:53:46 -0700312 } catch (InterruptedException e) {
313 }
314 }
315 }
316
317 Log.i(TAG, "Shutting down activity manager...");
318
319 final IActivityManager am =
320 ActivityManagerNative.asInterface(ServiceManager.checkService("activity"));
321 if (am != null) {
322 try {
323 am.shutdown(MAX_BROADCAST_TIME);
324 } catch (RemoteException e) {
325 }
326 }
327
Sunil Jogi3bba8d02012-04-10 13:12:26 -0700328 final INfcAdapter nfc =
329 INfcAdapter.Stub.asInterface(ServiceManager.checkService("nfc"));
Dianne Hackborn55280a92009-05-07 15:53:46 -0700330 final ITelephony phone =
331 ITelephony.Stub.asInterface(ServiceManager.checkService("phone"));
Nick Pellybd022f42009-08-14 18:33:38 -0700332 final IBluetooth bluetooth =
333 IBluetooth.Stub.asInterface(ServiceManager.checkService(
Nick Pellyf242b7b2009-10-08 00:12:45 +0200334 BluetoothAdapter.BLUETOOTH_SERVICE));
San Mehat9f7f7ca2010-01-07 11:34:59 -0800335 final IMountService mount =
336 IMountService.Stub.asInterface(
337 ServiceManager.checkService("mount"));
Sunil Jogi3bba8d02012-04-10 13:12:26 -0700338
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
Dianne Hackborn55280a92009-05-07 15:53:46 -0700351 try {
352 bluetoothOff = bluetooth == null ||
Nick Pellyde893f52009-09-08 13:15:33 -0700353 bluetooth.getBluetoothState() == BluetoothAdapter.STATE_OFF;
Dianne Hackborn55280a92009-05-07 15:53:46 -0700354 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
Sunil Jogi3bba8d02012-04-10 13:12:26 -0700374 Log.i(TAG, "Waiting for NFC, Bluetooth and Radio...");
Dianne Hackborn55280a92009-05-07 15:53:46 -0700375
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 =
Nick Pellyde893f52009-09-08 13:15:33 -0700381 bluetooth.getBluetoothState() == BluetoothAdapter.STATE_OFF;
Dianne Hackborn55280a92009-05-07 15:53:46 -0700382 } 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 }
Sunil Jogi3bba8d02012-04-10 13:12:26 -0700395 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 }
403
404 if (radioOff && bluetoothOff && nfcOff) {
405 Log.i(TAG, "NFC, Radio and Bluetooth shutdown complete.");
Dianne Hackborn55280a92009-05-07 15:53:46 -0700406 break;
407 }
408 SystemClock.sleep(PHONE_STATE_POLL_SLEEP_MSEC);
409 }
410
San Mehat9f7f7ca2010-01-07 11:34:59 -0800411 // Shutdown MountService to ensure media is in a safe state
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -0800412 IMountShutdownObserver observer = new IMountShutdownObserver.Stub() {
413 public void onShutDownComplete(int statusCode) throws RemoteException {
414 Log.w(TAG, "Result code " + statusCode + " from MountService.shutdown");
415 actionDone();
San Mehat9f7f7ca2010-01-07 11:34:59 -0800416 }
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -0800417 };
418
419 Log.i(TAG, "Shutting down MountService");
420 // Set initial variables and time out time.
421 mActionDone = false;
Mike Lockwood098e58d2010-05-13 16:29:49 -0400422 final long endShutTime = SystemClock.elapsedRealtime() + MAX_SHUTDOWN_WAIT_TIME;
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -0800423 synchronized (mActionDoneSync) {
424 try {
425 if (mount != null) {
426 mount.shutdown(observer);
427 } else {
428 Log.w(TAG, "MountService unavailable for shutdown");
429 }
430 } catch (Exception e) {
431 Log.e(TAG, "Exception during MountService shutdown", e);
432 }
433 while (!mActionDone) {
Mike Lockwood098e58d2010-05-13 16:29:49 -0400434 long delay = endShutTime - SystemClock.elapsedRealtime();
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -0800435 if (delay <= 0) {
436 Log.w(TAG, "Shutdown wait timed out");
437 break;
438 }
439 try {
440 mActionDoneSync.wait(delay);
441 } catch (InterruptedException e) {
442 }
443 }
San Mehat9f7f7ca2010-01-07 11:34:59 -0800444 }
445
Kenny Rootf547d672010-09-22 10:36:48 -0700446 rebootOrShutdown(mReboot, mRebootReason);
447 }
448
449 /**
450 * Do not call this directly. Use {@link #reboot(Context, String, boolean)}
451 * or {@link #shutdown(Context, boolean)} instead.
452 *
453 * @param reboot true to reboot or false to shutdown
454 * @param reason reason for reboot
455 */
456 public static void rebootOrShutdown(boolean reboot, String reason) {
457 if (reboot) {
458 Log.i(TAG, "Rebooting, reason: " + reason);
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -0800459 try {
Jeff Brown7304c342012-05-11 18:42:42 -0700460 PowerManagerService.lowLevelReboot(reason);
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -0800461 } catch (Exception e) {
462 Log.e(TAG, "Reboot failed, will attempt shutdown instead", e);
463 }
Mike Lockwooda717f642010-04-01 20:01:44 -0700464 } else if (SHUTDOWN_VIBRATE_MS > 0) {
465 // vibrate before shutting down
Jeff Brownc2346132012-04-13 01:55:38 -0700466 Vibrator vibrator = new SystemVibrator();
Brad Fitzpatrick26e9cf32010-10-19 09:33:09 -0700467 try {
468 vibrator.vibrate(SHUTDOWN_VIBRATE_MS);
469 } catch (Exception e) {
470 // Failure to vibrate shouldn't interrupt shutdown. Just log it.
471 Log.w(TAG, "Failed to vibrate during shutdown.", e);
472 }
473
Mike Lockwooda717f642010-04-01 20:01:44 -0700474 // vibrator is asynchronous so we need to wait to avoid shutting down too soon.
475 try {
476 Thread.sleep(SHUTDOWN_VIBRATE_MS);
Brad Fitzpatricke3316442010-10-14 19:40:56 -0700477 } catch (InterruptedException unused) {
Mike Lockwooda717f642010-04-01 20:01:44 -0700478 }
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -0800479 }
480
481 // Shutdown power
Dianne Hackborn55280a92009-05-07 15:53:46 -0700482 Log.i(TAG, "Performing low-level shutdown...");
Jeff Brown7304c342012-05-11 18:42:42 -0700483 PowerManagerService.lowLevelShutdown();
Dianne Hackborn55280a92009-05-07 15:53:46 -0700484 }
485}