blob: 6bf725e1a09f6cde71d701aa0960bc7154bfa744 [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
Tao Bao90237f72015-05-21 16:25:19 -070017
Jeff Brown4f8ecd82012-06-18 18:29:13 -070018package com.android.server.power;
Dianne Hackborn55280a92009-05-07 15:53:46 -070019
Joe Onoratod208e702010-10-08 16:22:43 -040020import android.app.AlertDialog;
21import android.app.Dialog;
Dianne Hackborn55280a92009-05-07 15:53:46 -070022import android.app.IActivityManager;
Lucas Dupin527aad12017-07-21 13:50:25 -070023import android.app.KeyguardManager;
Dianne Hackborn55280a92009-05-07 15:53:46 -070024import android.app.ProgressDialog;
Lucas Dupin527aad12017-07-21 13:50:25 -070025import android.app.WallpaperColors;
26import android.app.WallpaperManager;
Nick Pellybd022f42009-08-14 18:33:38 -070027import android.bluetooth.BluetoothAdapter;
fredc0f420372012-04-12 00:02:00 -070028import android.bluetooth.IBluetoothManager;
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;
Jason Monkfd279662017-06-29 19:37:48 -040034import android.graphics.Color;
35import android.graphics.drawable.ColorDrawable;
36import android.media.AudioAttributes;
Tao Baoe8a403d2015-12-31 07:44:55 -080037import android.os.FileUtils;
Dianne Hackborn55280a92009-05-07 15:53:46 -070038import android.os.Handler;
Dianne Hackbornf99ae762010-03-08 12:43:51 -080039import android.os.PowerManager;
Tao Baoe8a403d2015-12-31 07:44:55 -080040import android.os.RecoverySystem;
Dianne Hackborn55280a92009-05-07 15:53:46 -070041import android.os.RemoteException;
Dianne Hackborn55280a92009-05-07 15:53:46 -070042import android.os.ServiceManager;
43import android.os.SystemClock;
Kenny Rootf547d672010-09-22 10:36:48 -070044import android.os.SystemProperties;
Jason Monkfd279662017-06-29 19:37:48 -040045import android.os.SystemVibrator;
Fyodor Kupolov6e3461b2017-08-10 17:00:43 -070046import android.os.Trace;
Dianne Hackborn5ac72a22012-08-29 18:32:08 -070047import android.os.UserHandle;
Benjamin Franzbff46ba2015-03-05 18:33:51 +000048import android.os.UserManager;
Mike Lockwooda717f642010-04-01 20:01:44 -070049import android.os.Vibrator;
Sudheer Shanka2250d562016-11-07 15:41:02 -080050import android.os.storage.IStorageManager;
Jason Monkfd279662017-06-29 19:37:48 -040051import android.os.storage.IStorageShutdownObserver;
Fyodor Kupolov291f63b2017-08-25 16:59:08 -070052import android.util.ArrayMap;
Jason Monkfd279662017-06-29 19:37:48 -040053import android.util.Log;
Fyodor Kupolov6e3461b2017-08-10 17:00:43 -070054import android.util.TimingsTraceLog;
Jason Monkfd279662017-06-29 19:37:48 -040055import android.view.WindowManager;
Lucas Dupin527aad12017-07-21 13:50:25 -070056
Dianne Hackborn55280a92009-05-07 15:53:46 -070057import com.android.internal.telephony.ITelephony;
Jeff Sharkeyb4f36972017-08-02 14:33:04 -060058import com.android.server.RescueParty;
Jason Monkb4302182017-08-04 13:39:17 -040059import com.android.server.LocalServices;
Brian Carlstromff1ec4d2014-03-17 15:21:35 -070060import com.android.server.pm.PackageManagerService;
Jason Monkb4302182017-08-04 13:39:17 -040061import com.android.server.statusbar.StatusBarManagerInternal;
Jeff Brown7304c342012-05-11 18:42:42 -070062
Tao Bao90237f72015-05-21 16:25:19 -070063import java.io.File;
Fyodor Kupolov291f63b2017-08-25 16:59:08 -070064import java.io.FileOutputStream;
Tao Bao90237f72015-05-21 16:25:19 -070065import java.io.IOException;
Fyodor Kupolov291f63b2017-08-25 16:59:08 -070066import java.nio.charset.StandardCharsets;
Tao Bao90237f72015-05-21 16:25:19 -070067
Dianne Hackborn55280a92009-05-07 15:53:46 -070068public final class ShutdownThread extends Thread {
69 // constants
70 private static final String TAG = "ShutdownThread";
Fyodor Kupolov231d57d2017-11-14 17:41:53 -080071 private static final int ACTION_DONE_POLL_WAIT_MS = 500;
72 private static final int RADIOS_STATE_POLL_SLEEP_MS = 100;
Dianne Hackborn55280a92009-05-07 15:53:46 -070073 // maximum time we wait for the shutdown broadcast before going on.
74 private static final int MAX_BROADCAST_TIME = 10*1000;
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -080075 private static final int MAX_SHUTDOWN_WAIT_TIME = 20*1000;
Jeff Brownb8203712012-05-31 17:39:13 -070076 private static final int MAX_RADIO_WAIT_TIME = 12*1000;
Adam Seatonb57e6562016-08-30 22:14:47 +000077 private static final int MAX_UNCRYPT_WAIT_TIME = 15*60*1000;
Tao Bao81dce662015-06-03 11:42:31 -070078 // constants for progress bar. the values are roughly estimated based on timeout.
79 private static final int BROADCAST_STOP_PERCENT = 2;
80 private static final int ACTIVITY_MANAGER_STOP_PERCENT = 4;
81 private static final int PACKAGE_MANAGER_STOP_PERCENT = 6;
82 private static final int RADIO_STOP_PERCENT = 18;
83 private static final int MOUNT_SERVICE_STOP_PERCENT = 20;
Mike Lockwooda717f642010-04-01 20:01:44 -070084
85 // length of vibration before shutting down
86 private static final int SHUTDOWN_VIBRATE_MS = 500;
Tao Bao90237f72015-05-21 16:25:19 -070087
Dianne Hackborn55280a92009-05-07 15:53:46 -070088 // state tracking
Adam Lesinskia82b6262017-03-21 16:56:17 -070089 private static final Object sIsStartedGuard = new Object();
Dianne Hackborn55280a92009-05-07 15:53:46 -070090 private static boolean sIsStarted = false;
Tao Bao90237f72015-05-21 16:25:19 -070091
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -080092 private static boolean mReboot;
Dianne Hackborn19caadc2012-04-20 17:49:10 -070093 private static boolean mRebootSafeMode;
Tao Baoe8a403d2015-12-31 07:44:55 -080094 private static boolean mRebootHasProgressBar;
Yusuke Sato705ffd12015-07-21 15:52:11 -070095 private static String mReason;
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -080096
Kenny Rootf547d672010-09-22 10:36:48 -070097 // Provides shutdown assurance in case the system_server is killed
98 public static final String SHUTDOWN_ACTION_PROPERTY = "sys.shutdown.requested";
99
Dianne Hackborn19caadc2012-04-20 17:49:10 -0700100 // Indicates whether we are rebooting into safe mode
101 public static final String REBOOT_SAFEMODE_PROPERTY = "persist.sys.safemode";
dcashmanf44f5a42016-03-02 16:46:40 -0800102 public static final String RO_SAFEMODE_PROPERTY = "ro.sys.safemode";
Dianne Hackborn19caadc2012-04-20 17:49:10 -0700103
Dianne Hackborn55280a92009-05-07 15:53:46 -0700104 // static instance of this thread
105 private static final ShutdownThread sInstance = new ShutdownThread();
John Spurlock7b414672014-07-18 13:02:39 -0400106
107 private static final AudioAttributes VIBRATION_ATTRIBUTES = new AudioAttributes.Builder()
108 .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
109 .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
110 .build();
111
Fyodor Kupolov291f63b2017-08-25 16:59:08 -0700112 // Metrics that will be reported to tron after reboot
113 private static final ArrayMap<String, Long> TRON_METRICS = new ArrayMap<>();
114
115 // File to use for save metrics
116 private static final String METRICS_FILE_BASENAME = "/data/system/shutdown-metrics";
117
118 // Metrics names to be persisted in shutdown-metrics file
119 private static String METRIC_SYSTEM_SERVER = "shutdown_system_server";
120 private static String METRIC_SEND_BROADCAST = "shutdown_send_shutdown_broadcast";
121 private static String METRIC_AM = "shutdown_activity_manager";
122 private static String METRIC_PM = "shutdown_package_manager";
123 private static String METRIC_RADIOS = "shutdown_radios";
124 private static String METRIC_BT = "shutdown_bt";
125 private static String METRIC_RADIO = "shutdown_radio";
Fyodor Kupolov291f63b2017-08-25 16:59:08 -0700126 private static String METRIC_SM = "shutdown_storage_manager";
127
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -0800128 private final Object mActionDoneSync = new Object();
129 private boolean mActionDone;
Dianne Hackborn55280a92009-05-07 15:53:46 -0700130 private Context mContext;
Dianne Hackbornf99ae762010-03-08 12:43:51 -0800131 private PowerManager mPowerManager;
Mattias Larssoncd4e4272010-09-28 14:34:15 +0200132 private PowerManager.WakeLock mCpuWakeLock;
133 private PowerManager.WakeLock mScreenWakeLock;
Dianne Hackborn55280a92009-05-07 15:53:46 -0700134 private Handler mHandler;
Jean-Baptiste Queru6e85ad72012-06-11 12:20:36 -0700135
136 private static AlertDialog sConfirmDialog;
Tao Bao90237f72015-05-21 16:25:19 -0700137 private ProgressDialog mProgressDialog;
138
Dianne Hackborn55280a92009-05-07 15:53:46 -0700139 private ShutdownThread() {
140 }
Tao Bao90237f72015-05-21 16:25:19 -0700141
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -0800142 /**
Dianne Hackborn55280a92009-05-07 15:53:46 -0700143 * Request a clean shutdown, waiting for subsystems to clean up their
144 * state etc. Must be called from a Looper thread in which its UI
145 * is shown.
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -0800146 *
Adam Lesinskia82b6262017-03-21 16:56:17 -0700147 * @param context Context used to display the shutdown progress dialog. This must be a context
148 * suitable for displaying UI (aka Themable).
Yusuke Sato705ffd12015-07-21 15:52:11 -0700149 * @param reason code to pass to android_reboot() (e.g. "userrequested"), or null.
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -0800150 * @param confirm true if user confirmation is needed before shutting down.
Dianne Hackborn55280a92009-05-07 15:53:46 -0700151 */
Yusuke Sato705ffd12015-07-21 15:52:11 -0700152 public static void shutdown(final Context context, String reason, boolean confirm) {
Dianne Hackborn19caadc2012-04-20 17:49:10 -0700153 mReboot = false;
154 mRebootSafeMode = false;
Yusuke Sato705ffd12015-07-21 15:52:11 -0700155 mReason = reason;
Dianne Hackborn19caadc2012-04-20 17:49:10 -0700156 shutdownInner(context, confirm);
157 }
158
Adam Lesinskia82b6262017-03-21 16:56:17 -0700159 private static void shutdownInner(final Context context, boolean confirm) {
160 // ShutdownThread is called from many places, so best to verify here that the context passed
161 // in is themed.
162 context.assertRuntimeOverlayThemable();
163
Dianne Hackborn55280a92009-05-07 15:53:46 -0700164 // ensure that only one thread is trying to power down.
165 // any additional calls are just returned
Mike Lockwoodd67b2362010-07-26 07:18:21 -0400166 synchronized (sIsStartedGuard) {
Dianne Hackborn55280a92009-05-07 15:53:46 -0700167 if (sIsStarted) {
168 Log.d(TAG, "Request to shutdown already running, returning.");
169 return;
170 }
171 }
172
Joe Onoratod208e702010-10-08 16:22:43 -0400173 final int longPressBehavior = context.getResources().getInteger(
174 com.android.internal.R.integer.config_longPressOnPowerBehavior);
Dianne Hackborn19caadc2012-04-20 17:49:10 -0700175 final int resourceId = mRebootSafeMode
176 ? com.android.internal.R.string.reboot_safemode_confirm
177 : (longPressBehavior == 2
178 ? com.android.internal.R.string.shutdown_confirm_question
179 : com.android.internal.R.string.shutdown_confirm);
Joe Onoratod208e702010-10-08 16:22:43 -0400180
181 Log.d(TAG, "Notifying thread to start shutdown longPressBehavior=" + longPressBehavior);
Dianne Hackborn55280a92009-05-07 15:53:46 -0700182
183 if (confirm) {
Joe Onoratod208e702010-10-08 16:22:43 -0400184 final CloseDialogReceiver closer = new CloseDialogReceiver(context);
Jean-Baptiste Queru6e85ad72012-06-11 12:20:36 -0700185 if (sConfirmDialog != null) {
186 sConfirmDialog.dismiss();
187 }
188 sConfirmDialog = new AlertDialog.Builder(context)
Dianne Hackborn19caadc2012-04-20 17:49:10 -0700189 .setTitle(mRebootSafeMode
190 ? com.android.internal.R.string.reboot_safemode_title
191 : com.android.internal.R.string.power_off)
Joe Onoratod208e702010-10-08 16:22:43 -0400192 .setMessage(resourceId)
Dianne Hackborn55280a92009-05-07 15:53:46 -0700193 .setPositiveButton(com.android.internal.R.string.yes, new DialogInterface.OnClickListener() {
194 public void onClick(DialogInterface dialog, int which) {
195 beginShutdownSequence(context);
196 }
197 })
198 .setNegativeButton(com.android.internal.R.string.no, null)
199 .create();
Jean-Baptiste Queru6e85ad72012-06-11 12:20:36 -0700200 closer.dialog = sConfirmDialog;
201 sConfirmDialog.setOnDismissListener(closer);
202 sConfirmDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
203 sConfirmDialog.show();
Dianne Hackborn55280a92009-05-07 15:53:46 -0700204 } else {
205 beginShutdownSequence(context);
206 }
207 }
208
Joe Onoratod208e702010-10-08 16:22:43 -0400209 private static class CloseDialogReceiver extends BroadcastReceiver
210 implements DialogInterface.OnDismissListener {
211 private Context mContext;
212 public Dialog dialog;
213
214 CloseDialogReceiver(Context context) {
215 mContext = context;
216 IntentFilter filter = new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
217 context.registerReceiver(this, filter);
218 }
219
220 @Override
221 public void onReceive(Context context, Intent intent) {
222 dialog.cancel();
223 }
224
225 public void onDismiss(DialogInterface unused) {
226 mContext.unregisterReceiver(this);
227 }
228 }
229
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -0800230 /**
231 * Request a clean shutdown, waiting for subsystems to clean up their
232 * state etc. Must be called from a Looper thread in which its UI
233 * is shown.
234 *
Adam Lesinskia82b6262017-03-21 16:56:17 -0700235 * @param context Context used to display the shutdown progress dialog. This must be a context
236 * suitable for displaying UI (aka Themable).
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -0800237 * @param reason code to pass to the kernel (e.g. "recovery"), or null.
238 * @param confirm true if user confirmation is needed before shutting down.
239 */
240 public static void reboot(final Context context, String reason, boolean confirm) {
241 mReboot = true;
Dianne Hackborn19caadc2012-04-20 17:49:10 -0700242 mRebootSafeMode = false;
Tao Baoe8a403d2015-12-31 07:44:55 -0800243 mRebootHasProgressBar = false;
Yusuke Sato705ffd12015-07-21 15:52:11 -0700244 mReason = reason;
Dianne Hackborn19caadc2012-04-20 17:49:10 -0700245 shutdownInner(context, confirm);
246 }
247
248 /**
249 * Request a reboot into safe mode. Must be called from a Looper thread in which its UI
250 * is shown.
251 *
Adam Lesinskia82b6262017-03-21 16:56:17 -0700252 * @param context Context used to display the shutdown progress dialog. This must be a context
253 * suitable for displaying UI (aka Themable).
Dianne Hackborn19caadc2012-04-20 17:49:10 -0700254 * @param confirm true if user confirmation is needed before shutting down.
255 */
256 public static void rebootSafeMode(final Context context, boolean confirm) {
Benjamin Franzbff46ba2015-03-05 18:33:51 +0000257 UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE);
258 if (um.hasUserRestriction(UserManager.DISALLOW_SAFE_BOOT)) {
259 return;
260 }
261
Dianne Hackborn19caadc2012-04-20 17:49:10 -0700262 mReboot = true;
263 mRebootSafeMode = true;
Tao Baoe8a403d2015-12-31 07:44:55 -0800264 mRebootHasProgressBar = false;
Yusuke Sato705ffd12015-07-21 15:52:11 -0700265 mReason = null;
Dianne Hackborn19caadc2012-04-20 17:49:10 -0700266 shutdownInner(context, confirm);
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -0800267 }
268
Jason Monkfd279662017-06-29 19:37:48 -0400269 private static ProgressDialog showShutdownDialog(Context context) {
Tao Bao81dce662015-06-03 11:42:31 -0700270 // Throw up a system dialog to indicate the device is rebooting / shutting down.
Dianne Hackborn55280a92009-05-07 15:53:46 -0700271 ProgressDialog pd = new ProgressDialog(context);
Tao Bao81dce662015-06-03 11:42:31 -0700272
Tao Baoe8a403d2015-12-31 07:44:55 -0800273 // Path 1: Reboot to recovery for update
Tianjie Xu3a66fc42017-06-09 15:50:14 -0700274 // Condition: mReason startswith REBOOT_RECOVERY_UPDATE
Tao Baoe8a403d2015-12-31 07:44:55 -0800275 //
276 // Path 1a: uncrypt needed
277 // Condition: if /cache/recovery/uncrypt_file exists but
278 // /cache/recovery/block.map doesn't.
279 // UI: determinate progress bar (mRebootHasProgressBar == True)
280 //
281 // * Path 1a is expected to be removed once the GmsCore shipped on
282 // device always calls uncrypt prior to reboot.
283 //
284 // Path 1b: uncrypt already done
285 // UI: spinning circle only (no progress bar)
Tao Bao81dce662015-06-03 11:42:31 -0700286 //
287 // Path 2: Reboot to recovery for factory reset
Yusuke Sato705ffd12015-07-21 15:52:11 -0700288 // Condition: mReason == REBOOT_RECOVERY
Tao Bao81dce662015-06-03 11:42:31 -0700289 // UI: spinning circle only (no progress bar)
290 //
291 // Path 3: Regular reboot / shutdown
292 // Condition: Otherwise
293 // UI: spinning circle only (no progress bar)
Tianjie Xu3a66fc42017-06-09 15:50:14 -0700294
295 // mReason could be "recovery-update" or "recovery-update,quiescent".
296 if (mReason != null && mReason.startsWith(PowerManager.REBOOT_RECOVERY_UPDATE)) {
Tao Baoe8a403d2015-12-31 07:44:55 -0800297 // We need the progress bar if uncrypt will be invoked during the
298 // reboot, which might be time-consuming.
299 mRebootHasProgressBar = RecoverySystem.UNCRYPT_PACKAGE_FILE.exists()
300 && !(RecoverySystem.BLOCK_MAP_FILE.exists());
301 pd.setTitle(context.getText(com.android.internal.R.string.reboot_to_update_title));
302 if (mRebootHasProgressBar) {
Tao Bao81dce662015-06-03 11:42:31 -0700303 pd.setMax(100);
Tao Bao81dce662015-06-03 11:42:31 -0700304 pd.setProgress(0);
305 pd.setIndeterminate(false);
Tao Baoe8a403d2015-12-31 07:44:55 -0800306 pd.setProgressNumberFormat(null);
307 pd.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
Tao Bao81dce662015-06-03 11:42:31 -0700308 pd.setMessage(context.getText(
Tao Baoe8a403d2015-12-31 07:44:55 -0800309 com.android.internal.R.string.reboot_to_update_prepare));
310 } else {
Jason Monkb4302182017-08-04 13:39:17 -0400311 if (showSysuiReboot()) {
312 return null;
313 }
Tao Bao81dce662015-06-03 11:42:31 -0700314 pd.setIndeterminate(true);
Tao Baoe8a403d2015-12-31 07:44:55 -0800315 pd.setMessage(context.getText(
316 com.android.internal.R.string.reboot_to_update_reboot));
Tao Bao81dce662015-06-03 11:42:31 -0700317 }
Tianjie Xu3a66fc42017-06-09 15:50:14 -0700318 } else if (mReason != null && mReason.equals(PowerManager.REBOOT_RECOVERY)) {
Jeff Sharkeyb4f36972017-08-02 14:33:04 -0600319 if (RescueParty.isAttemptingFactoryReset()) {
320 // We're not actually doing a factory reset yet; we're rebooting
321 // to ask the user if they'd like to reset, so give them a less
322 // scary dialog message.
323 pd.setTitle(context.getText(com.android.internal.R.string.power_off));
324 pd.setMessage(context.getText(com.android.internal.R.string.shutdown_progress));
325 pd.setIndeterminate(true);
326 } else {
327 // Factory reset path. Set the dialog message accordingly.
328 pd.setTitle(context.getText(com.android.internal.R.string.reboot_to_reset_title));
329 pd.setMessage(context.getText(
330 com.android.internal.R.string.reboot_to_reset_message));
331 pd.setIndeterminate(true);
332 }
Tao Bao90237f72015-05-21 16:25:19 -0700333 } else {
Jason Monkb4302182017-08-04 13:39:17 -0400334 if (showSysuiReboot()) {
335 return null;
336 }
Tao Bao90237f72015-05-21 16:25:19 -0700337 pd.setTitle(context.getText(com.android.internal.R.string.power_off));
Tao Bao81dce662015-06-03 11:42:31 -0700338 pd.setMessage(context.getText(com.android.internal.R.string.shutdown_progress));
339 pd.setIndeterminate(true);
Tao Bao90237f72015-05-21 16:25:19 -0700340 }
Dianne Hackborn55280a92009-05-07 15:53:46 -0700341 pd.setCancelable(false);
342 pd.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
Dianne Hackborn55280a92009-05-07 15:53:46 -0700343
344 pd.show();
Jason Monkfd279662017-06-29 19:37:48 -0400345 return pd;
346 }
Dianne Hackborn55280a92009-05-07 15:53:46 -0700347
Jason Monkb4302182017-08-04 13:39:17 -0400348 private static boolean showSysuiReboot() {
349 Log.d(TAG, "Attempting to use SysUI shutdown UI");
350 try {
351 StatusBarManagerInternal service = LocalServices.getService(
352 StatusBarManagerInternal.class);
353 if (service.showShutdownUi(mReboot, mReason)) {
354 // Sysui will handle shutdown UI.
355 Log.d(TAG, "SysUI handling shutdown UI");
356 return true;
357 }
358 } catch (Exception e) {
359 // If anything went wrong, ignore it and use fallback ui
360 }
361 Log.d(TAG, "SysUI is unavailable");
362 return false;
363 }
364
Jason Monkfd279662017-06-29 19:37:48 -0400365 private static void beginShutdownSequence(Context context) {
366 synchronized (sIsStartedGuard) {
367 if (sIsStarted) {
368 Log.d(TAG, "Shutdown sequence already running, returning.");
369 return;
370 }
371 sIsStarted = true;
372 }
373
374 sInstance.mProgressDialog = showShutdownDialog(context);
Dianne Hackborn55280a92009-05-07 15:53:46 -0700375 sInstance.mContext = context;
Dianne Hackbornf99ae762010-03-08 12:43:51 -0800376 sInstance.mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
Mattias Larssoncd4e4272010-09-28 14:34:15 +0200377
378 // make sure we never fall asleep again
379 sInstance.mCpuWakeLock = null;
380 try {
381 sInstance.mCpuWakeLock = sInstance.mPowerManager.newWakeLock(
382 PowerManager.PARTIAL_WAKE_LOCK, TAG + "-cpu");
383 sInstance.mCpuWakeLock.setReferenceCounted(false);
384 sInstance.mCpuWakeLock.acquire();
385 } catch (SecurityException e) {
386 Log.w(TAG, "No permission to acquire wake lock", e);
387 sInstance.mCpuWakeLock = null;
388 }
389
390 // also make sure the screen stays on for better user experience
391 sInstance.mScreenWakeLock = null;
Dianne Hackbornf99ae762010-03-08 12:43:51 -0800392 if (sInstance.mPowerManager.isScreenOn()) {
393 try {
Mattias Larssoncd4e4272010-09-28 14:34:15 +0200394 sInstance.mScreenWakeLock = sInstance.mPowerManager.newWakeLock(
395 PowerManager.FULL_WAKE_LOCK, TAG + "-screen");
396 sInstance.mScreenWakeLock.setReferenceCounted(false);
397 sInstance.mScreenWakeLock.acquire();
Dianne Hackbornf99ae762010-03-08 12:43:51 -0800398 } catch (SecurityException e) {
399 Log.w(TAG, "No permission to acquire wake lock", e);
Mattias Larssoncd4e4272010-09-28 14:34:15 +0200400 sInstance.mScreenWakeLock = null;
Dianne Hackbornf99ae762010-03-08 12:43:51 -0800401 }
402 }
Mattias Larssoncd4e4272010-09-28 14:34:15 +0200403
404 // start the thread that initiates shutdown
Dianne Hackborn55280a92009-05-07 15:53:46 -0700405 sInstance.mHandler = new Handler() {
406 };
407 sInstance.start();
408 }
409
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -0800410 void actionDone() {
411 synchronized (mActionDoneSync) {
412 mActionDone = true;
413 mActionDoneSync.notifyAll();
Dianne Hackborn55280a92009-05-07 15:53:46 -0700414 }
415 }
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -0800416
Dianne Hackborn55280a92009-05-07 15:53:46 -0700417 /**
418 * Makes sure we handle the shutdown gracefully.
419 * Shuts off power regardless of radio and bluetooth state if the alloted time has passed.
420 */
421 public void run() {
Fyodor Kupolov58815ea2017-08-29 12:12:03 -0700422 TimingsTraceLog shutdownTimingLog = newTimingsLog();
423 shutdownTimingLog.traceBegin("SystemServerShutdown");
424 metricStarted(METRIC_SYSTEM_SERVER);
425
Dianne Hackborn55280a92009-05-07 15:53:46 -0700426 BroadcastReceiver br = new BroadcastReceiver() {
427 @Override public void onReceive(Context context, Intent intent) {
428 // We don't allow apps to cancel this, so ignore the result.
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -0800429 actionDone();
Dianne Hackborn55280a92009-05-07 15:53:46 -0700430 }
431 };
Kenny Rootf547d672010-09-22 10:36:48 -0700432
433 /*
434 * Write a system property in case the system_server reboots before we
435 * get to the actual hardware restart. If that happens, we'll retry at
436 * the beginning of the SystemServer startup.
437 */
438 {
Yusuke Sato705ffd12015-07-21 15:52:11 -0700439 String reason = (mReboot ? "1" : "0") + (mReason != null ? mReason : "");
Kenny Rootf547d672010-09-22 10:36:48 -0700440 SystemProperties.set(SHUTDOWN_ACTION_PROPERTY, reason);
441 }
442
Dianne Hackborn19caadc2012-04-20 17:49:10 -0700443 /*
444 * If we are rebooting into safe mode, write a system property
445 * indicating so.
446 */
447 if (mRebootSafeMode) {
448 SystemProperties.set(REBOOT_SAFEMODE_PROPERTY, "1");
449 }
450
Fyodor Kupolov291f63b2017-08-25 16:59:08 -0700451 metricStarted(METRIC_SEND_BROADCAST);
Fyodor Kupolov58815ea2017-08-29 12:12:03 -0700452 shutdownTimingLog.traceBegin("SendShutdownBroadcast");
Dianne Hackborn55280a92009-05-07 15:53:46 -0700453 Log.i(TAG, "Sending shutdown broadcast...");
Tao Bao90237f72015-05-21 16:25:19 -0700454
Dianne Hackborn55280a92009-05-07 15:53:46 -0700455 // First send the high-level shut down broadcast.
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -0800456 mActionDone = false;
Martin Wallgrena81d7da2013-02-04 14:26:51 +0100457 Intent intent = new Intent(Intent.ACTION_SHUTDOWN);
Fyodor Kupolov06aea9d2017-10-06 16:28:49 -0700458 intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
Martin Wallgrena81d7da2013-02-04 14:26:51 +0100459 mContext.sendOrderedBroadcastAsUser(intent,
Dianne Hackborn5ac72a22012-08-29 18:32:08 -0700460 UserHandle.ALL, null, br, mHandler, 0, null, null);
Tao Bao90237f72015-05-21 16:25:19 -0700461
Mike Lockwood098e58d2010-05-13 16:29:49 -0400462 final long endTime = SystemClock.elapsedRealtime() + MAX_BROADCAST_TIME;
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -0800463 synchronized (mActionDoneSync) {
464 while (!mActionDone) {
Mike Lockwood098e58d2010-05-13 16:29:49 -0400465 long delay = endTime - SystemClock.elapsedRealtime();
Dianne Hackborn55280a92009-05-07 15:53:46 -0700466 if (delay <= 0) {
467 Log.w(TAG, "Shutdown broadcast timed out");
468 break;
Tao Baoe8a403d2015-12-31 07:44:55 -0800469 } else if (mRebootHasProgressBar) {
Tao Bao81dce662015-06-03 11:42:31 -0700470 int status = (int)((MAX_BROADCAST_TIME - delay) * 1.0 *
471 BROADCAST_STOP_PERCENT / MAX_BROADCAST_TIME);
472 sInstance.setRebootProgress(status, null);
Dianne Hackborn55280a92009-05-07 15:53:46 -0700473 }
474 try {
Fyodor Kupolov231d57d2017-11-14 17:41:53 -0800475 mActionDoneSync.wait(Math.min(delay, ACTION_DONE_POLL_WAIT_MS));
Dianne Hackborn55280a92009-05-07 15:53:46 -0700476 } catch (InterruptedException e) {
477 }
478 }
479 }
Tao Baoe8a403d2015-12-31 07:44:55 -0800480 if (mRebootHasProgressBar) {
Tao Bao81dce662015-06-03 11:42:31 -0700481 sInstance.setRebootProgress(BROADCAST_STOP_PERCENT, null);
482 }
Fyodor Kupolov58815ea2017-08-29 12:12:03 -0700483 shutdownTimingLog.traceEnd(); // SendShutdownBroadcast
Fyodor Kupolov291f63b2017-08-25 16:59:08 -0700484 metricEnded(METRIC_SEND_BROADCAST);
Tao Bao90237f72015-05-21 16:25:19 -0700485
Dianne Hackborn55280a92009-05-07 15:53:46 -0700486 Log.i(TAG, "Shutting down activity manager...");
Fyodor Kupolov58815ea2017-08-29 12:12:03 -0700487 shutdownTimingLog.traceBegin("ShutdownActivityManager");
Fyodor Kupolov291f63b2017-08-25 16:59:08 -0700488 metricStarted(METRIC_AM);
Tao Bao90237f72015-05-21 16:25:19 -0700489
Dianne Hackborn55280a92009-05-07 15:53:46 -0700490 final IActivityManager am =
Sudheer Shankafc46e9b2016-10-21 17:55:27 -0700491 IActivityManager.Stub.asInterface(ServiceManager.checkService("activity"));
Dianne Hackborn55280a92009-05-07 15:53:46 -0700492 if (am != null) {
493 try {
494 am.shutdown(MAX_BROADCAST_TIME);
495 } catch (RemoteException e) {
496 }
497 }
Tao Baoe8a403d2015-12-31 07:44:55 -0800498 if (mRebootHasProgressBar) {
Tao Bao81dce662015-06-03 11:42:31 -0700499 sInstance.setRebootProgress(ACTIVITY_MANAGER_STOP_PERCENT, null);
500 }
Fyodor Kupolov58815ea2017-08-29 12:12:03 -0700501 shutdownTimingLog.traceEnd();// ShutdownActivityManager
Fyodor Kupolov291f63b2017-08-25 16:59:08 -0700502 metricEnded(METRIC_AM);
Dianne Hackborn55280a92009-05-07 15:53:46 -0700503
Brian Carlstromff1ec4d2014-03-17 15:21:35 -0700504 Log.i(TAG, "Shutting down package manager...");
Fyodor Kupolov58815ea2017-08-29 12:12:03 -0700505 shutdownTimingLog.traceBegin("ShutdownPackageManager");
Fyodor Kupolov291f63b2017-08-25 16:59:08 -0700506 metricStarted(METRIC_PM);
Brian Carlstromff1ec4d2014-03-17 15:21:35 -0700507
508 final PackageManagerService pm = (PackageManagerService)
509 ServiceManager.getService("package");
510 if (pm != null) {
511 pm.shutdown();
512 }
Tao Baoe8a403d2015-12-31 07:44:55 -0800513 if (mRebootHasProgressBar) {
Tao Bao81dce662015-06-03 11:42:31 -0700514 sInstance.setRebootProgress(PACKAGE_MANAGER_STOP_PERCENT, null);
515 }
Fyodor Kupolov58815ea2017-08-29 12:12:03 -0700516 shutdownTimingLog.traceEnd(); // ShutdownPackageManager
Fyodor Kupolov291f63b2017-08-25 16:59:08 -0700517 metricEnded(METRIC_PM);
Brian Carlstromff1ec4d2014-03-17 15:21:35 -0700518
Matthew Xie96313142012-06-29 16:57:31 -0700519 // Shutdown radios.
Fyodor Kupolov58815ea2017-08-29 12:12:03 -0700520 shutdownTimingLog.traceBegin("ShutdownRadios");
Fyodor Kupolov291f63b2017-08-25 16:59:08 -0700521 metricStarted(METRIC_RADIOS);
Matthew Xie96313142012-06-29 16:57:31 -0700522 shutdownRadios(MAX_RADIO_WAIT_TIME);
Tao Baoe8a403d2015-12-31 07:44:55 -0800523 if (mRebootHasProgressBar) {
Tao Bao81dce662015-06-03 11:42:31 -0700524 sInstance.setRebootProgress(RADIO_STOP_PERCENT, null);
525 }
Fyodor Kupolov58815ea2017-08-29 12:12:03 -0700526 shutdownTimingLog.traceEnd(); // ShutdownRadios
Fyodor Kupolov291f63b2017-08-25 16:59:08 -0700527 metricEnded(METRIC_RADIOS);
Matthew Xie96313142012-06-29 16:57:31 -0700528
Sudheer Shanka2250d562016-11-07 15:41:02 -0800529 // Shutdown StorageManagerService to ensure media is in a safe state
530 IStorageShutdownObserver observer = new IStorageShutdownObserver.Stub() {
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -0800531 public void onShutDownComplete(int statusCode) throws RemoteException {
Sudheer Shanka2250d562016-11-07 15:41:02 -0800532 Log.w(TAG, "Result code " + statusCode + " from StorageManagerService.shutdown");
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -0800533 actionDone();
San Mehat9f7f7ca2010-01-07 11:34:59 -0800534 }
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -0800535 };
536
Sudheer Shanka2250d562016-11-07 15:41:02 -0800537 Log.i(TAG, "Shutting down StorageManagerService");
Fyodor Kupolov58815ea2017-08-29 12:12:03 -0700538 shutdownTimingLog.traceBegin("ShutdownStorageManager");
Fyodor Kupolov291f63b2017-08-25 16:59:08 -0700539 metricStarted(METRIC_SM);
Jeff Brownb8203712012-05-31 17:39:13 -0700540
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -0800541 // Set initial variables and time out time.
542 mActionDone = false;
Mike Lockwood098e58d2010-05-13 16:29:49 -0400543 final long endShutTime = SystemClock.elapsedRealtime() + MAX_SHUTDOWN_WAIT_TIME;
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -0800544 synchronized (mActionDoneSync) {
545 try {
Sudheer Shanka2250d562016-11-07 15:41:02 -0800546 final IStorageManager storageManager = IStorageManager.Stub.asInterface(
Jeff Brownb8203712012-05-31 17:39:13 -0700547 ServiceManager.checkService("mount"));
Sudheer Shanka2250d562016-11-07 15:41:02 -0800548 if (storageManager != null) {
549 storageManager.shutdown(observer);
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -0800550 } else {
Sudheer Shanka2250d562016-11-07 15:41:02 -0800551 Log.w(TAG, "StorageManagerService unavailable for shutdown");
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -0800552 }
553 } catch (Exception e) {
Sudheer Shanka2250d562016-11-07 15:41:02 -0800554 Log.e(TAG, "Exception during StorageManagerService shutdown", e);
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -0800555 }
556 while (!mActionDone) {
Mike Lockwood098e58d2010-05-13 16:29:49 -0400557 long delay = endShutTime - SystemClock.elapsedRealtime();
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -0800558 if (delay <= 0) {
Fyodor Kupolov6e3461b2017-08-10 17:00:43 -0700559 Log.w(TAG, "StorageManager shutdown wait timed out");
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -0800560 break;
Tao Baoe8a403d2015-12-31 07:44:55 -0800561 } else if (mRebootHasProgressBar) {
Tao Bao81dce662015-06-03 11:42:31 -0700562 int status = (int)((MAX_SHUTDOWN_WAIT_TIME - delay) * 1.0 *
563 (MOUNT_SERVICE_STOP_PERCENT - RADIO_STOP_PERCENT) /
564 MAX_SHUTDOWN_WAIT_TIME);
565 status += RADIO_STOP_PERCENT;
566 sInstance.setRebootProgress(status, null);
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -0800567 }
568 try {
Fyodor Kupolov231d57d2017-11-14 17:41:53 -0800569 mActionDoneSync.wait(Math.min(delay, ACTION_DONE_POLL_WAIT_MS));
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -0800570 } catch (InterruptedException e) {
571 }
572 }
San Mehat9f7f7ca2010-01-07 11:34:59 -0800573 }
Fyodor Kupolov58815ea2017-08-29 12:12:03 -0700574 shutdownTimingLog.traceEnd(); // ShutdownStorageManager
Fyodor Kupolov291f63b2017-08-25 16:59:08 -0700575 metricEnded(METRIC_SM);
Fyodor Kupolov6e3461b2017-08-10 17:00:43 -0700576
Tao Baoe8a403d2015-12-31 07:44:55 -0800577 if (mRebootHasProgressBar) {
Tao Bao81dce662015-06-03 11:42:31 -0700578 sInstance.setRebootProgress(MOUNT_SERVICE_STOP_PERCENT, null);
San Mehat9f7f7ca2010-01-07 11:34:59 -0800579
Tao Baoe8a403d2015-12-31 07:44:55 -0800580 // If it's to reboot to install an update and uncrypt hasn't been
581 // done yet, trigger it now.
Tao Bao90237f72015-05-21 16:25:19 -0700582 uncrypt();
583 }
584
Fyodor Kupolov58815ea2017-08-29 12:12:03 -0700585 shutdownTimingLog.traceEnd(); // SystemServerShutdown
586 metricEnded(METRIC_SYSTEM_SERVER);
587 saveMetrics(mReboot);
Yusuke Sato705ffd12015-07-21 15:52:11 -0700588 rebootOrShutdown(mContext, mReboot, mReason);
Kenny Rootf547d672010-09-22 10:36:48 -0700589 }
590
Fyodor Kupolov58815ea2017-08-29 12:12:03 -0700591 private static TimingsTraceLog newTimingsLog() {
592 return new TimingsTraceLog("ShutdownTiming", Trace.TRACE_TAG_SYSTEM_SERVER);
593 }
594
Fyodor Kupolov291f63b2017-08-25 16:59:08 -0700595 private static void metricStarted(String metricKey) {
Fyodor Kupolov58815ea2017-08-29 12:12:03 -0700596 synchronized (TRON_METRICS) {
597 TRON_METRICS.put(metricKey, -1 * SystemClock.elapsedRealtime());
598 }
Fyodor Kupolov291f63b2017-08-25 16:59:08 -0700599 }
600
601 private static void metricEnded(String metricKey) {
Fyodor Kupolov58815ea2017-08-29 12:12:03 -0700602 synchronized (TRON_METRICS) {
603 TRON_METRICS
604 .put(metricKey, SystemClock.elapsedRealtime() + TRON_METRICS.get(metricKey));
605 }
Fyodor Kupolov291f63b2017-08-25 16:59:08 -0700606 }
607
Tao Bao81dce662015-06-03 11:42:31 -0700608 private void setRebootProgress(final int progress, final CharSequence message) {
Tao Bao90237f72015-05-21 16:25:19 -0700609 mHandler.post(new Runnable() {
610 @Override
611 public void run() {
612 if (mProgressDialog != null) {
613 mProgressDialog.setProgress(progress);
Tao Bao81dce662015-06-03 11:42:31 -0700614 if (message != null) {
615 mProgressDialog.setMessage(message);
616 }
Tao Bao90237f72015-05-21 16:25:19 -0700617 }
618 }
619 });
620 }
621
Tao Bao81dce662015-06-03 11:42:31 -0700622 private void shutdownRadios(final int timeout) {
Jeff Brownb8203712012-05-31 17:39:13 -0700623 // If a radio is wedged, disabling it may hang so we do this work in another thread,
624 // just in case.
625 final long endTime = SystemClock.elapsedRealtime() + timeout;
626 final boolean[] done = new boolean[1];
627 Thread t = new Thread() {
628 public void run() {
Fyodor Kupolov58815ea2017-08-29 12:12:03 -0700629 TimingsTraceLog shutdownTimingsTraceLog = newTimingsLog();
Wei Wang4d282542017-08-07 15:35:13 -0700630 boolean bluetoothReadyForShutdown;
Jeff Brownb8203712012-05-31 17:39:13 -0700631 boolean radioOff;
632
Jeff Brownb8203712012-05-31 17:39:13 -0700633 final ITelephony phone =
634 ITelephony.Stub.asInterface(ServiceManager.checkService("phone"));
Matthew Xie96313142012-06-29 16:57:31 -0700635 final IBluetoothManager bluetooth =
636 IBluetoothManager.Stub.asInterface(ServiceManager.checkService(
637 BluetoothAdapter.BLUETOOTH_MANAGER_SERVICE));
Jeff Brownb8203712012-05-31 17:39:13 -0700638
639 try {
Wei Wang4d282542017-08-07 15:35:13 -0700640 bluetoothReadyForShutdown = bluetooth == null ||
Christine Hallstrom995c90a2016-05-25 15:49:08 -0700641 bluetooth.getState() == BluetoothAdapter.STATE_OFF;
Wei Wang4d282542017-08-07 15:35:13 -0700642 if (!bluetoothReadyForShutdown) {
Jeff Brownb8203712012-05-31 17:39:13 -0700643 Log.w(TAG, "Disabling Bluetooth...");
Fyodor Kupolov291f63b2017-08-25 16:59:08 -0700644 metricStarted(METRIC_BT);
Svetoslav Ganovac69be52016-06-29 17:31:44 -0700645 bluetooth.disable(mContext.getPackageName(), false); // disable but don't persist new state
Jeff Brownb8203712012-05-31 17:39:13 -0700646 }
647 } catch (RemoteException ex) {
648 Log.e(TAG, "RemoteException during bluetooth shutdown", ex);
Wei Wang4d282542017-08-07 15:35:13 -0700649 bluetoothReadyForShutdown = true;
Jeff Brownb8203712012-05-31 17:39:13 -0700650 }
651
652 try {
Naveen Kallabd772362014-08-02 01:03:42 -0700653 radioOff = phone == null || !phone.needMobileRadioShutdown();
Jeff Brownb8203712012-05-31 17:39:13 -0700654 if (!radioOff) {
Naveen Kallabd772362014-08-02 01:03:42 -0700655 Log.w(TAG, "Turning off cellular radios...");
Fyodor Kupolov291f63b2017-08-25 16:59:08 -0700656 metricStarted(METRIC_RADIO);
Naveen Kallabd772362014-08-02 01:03:42 -0700657 phone.shutdownMobileRadios();
Jeff Brownb8203712012-05-31 17:39:13 -0700658 }
659 } catch (RemoteException ex) {
660 Log.e(TAG, "RemoteException during radio shutdown", ex);
661 radioOff = true;
662 }
663
Ruchi Kandoi20bc30f2017-10-18 13:06:40 -0700664 Log.i(TAG, "Waiting for Bluetooth and Radio...");
Jeff Brownb8203712012-05-31 17:39:13 -0700665
Tao Bao81dce662015-06-03 11:42:31 -0700666 long delay = endTime - SystemClock.elapsedRealtime();
667 while (delay > 0) {
Tao Baoe8a403d2015-12-31 07:44:55 -0800668 if (mRebootHasProgressBar) {
Tao Bao81dce662015-06-03 11:42:31 -0700669 int status = (int)((timeout - delay) * 1.0 *
670 (RADIO_STOP_PERCENT - PACKAGE_MANAGER_STOP_PERCENT) / timeout);
671 status += PACKAGE_MANAGER_STOP_PERCENT;
672 sInstance.setRebootProgress(status, null);
673 }
674
Wei Wang4d282542017-08-07 15:35:13 -0700675 if (!bluetoothReadyForShutdown) {
Jeff Brownb8203712012-05-31 17:39:13 -0700676 try {
Wei Wang4d282542017-08-07 15:35:13 -0700677 // BLE only mode can happen when BT is turned off
678 // We will continue shutting down in such case
679 bluetoothReadyForShutdown =
680 bluetooth.getState() == BluetoothAdapter.STATE_OFF ||
681 bluetooth.getState() == BluetoothAdapter.STATE_BLE_TURNING_OFF ||
682 bluetooth.getState() == BluetoothAdapter.STATE_BLE_ON;
Jeff Brownb8203712012-05-31 17:39:13 -0700683 } catch (RemoteException ex) {
684 Log.e(TAG, "RemoteException during bluetooth shutdown", ex);
Wei Wang4d282542017-08-07 15:35:13 -0700685 bluetoothReadyForShutdown = true;
Jeff Brownb8203712012-05-31 17:39:13 -0700686 }
Wei Wang4d282542017-08-07 15:35:13 -0700687 if (bluetoothReadyForShutdown) {
Jeff Brownb8203712012-05-31 17:39:13 -0700688 Log.i(TAG, "Bluetooth turned off.");
Fyodor Kupolov291f63b2017-08-25 16:59:08 -0700689 metricEnded(METRIC_BT);
Fyodor Kupolov58815ea2017-08-29 12:12:03 -0700690 shutdownTimingsTraceLog
Fyodor Kupolov291f63b2017-08-25 16:59:08 -0700691 .logDuration("ShutdownBt", TRON_METRICS.get(METRIC_BT));
Jeff Brownb8203712012-05-31 17:39:13 -0700692 }
693 }
694 if (!radioOff) {
695 try {
Naveen Kallabd772362014-08-02 01:03:42 -0700696 radioOff = !phone.needMobileRadioShutdown();
Jeff Brownb8203712012-05-31 17:39:13 -0700697 } catch (RemoteException ex) {
698 Log.e(TAG, "RemoteException during radio shutdown", ex);
699 radioOff = true;
700 }
701 if (radioOff) {
702 Log.i(TAG, "Radio turned off.");
Fyodor Kupolov291f63b2017-08-25 16:59:08 -0700703 metricEnded(METRIC_RADIO);
Fyodor Kupolov58815ea2017-08-29 12:12:03 -0700704 shutdownTimingsTraceLog
Fyodor Kupolov291f63b2017-08-25 16:59:08 -0700705 .logDuration("ShutdownRadio", TRON_METRICS.get(METRIC_RADIO));
Jeff Brownb8203712012-05-31 17:39:13 -0700706 }
707 }
Jeff Brownb8203712012-05-31 17:39:13 -0700708
Ruchi Kandoi20bc30f2017-10-18 13:06:40 -0700709 if (radioOff && bluetoothReadyForShutdown) {
710 Log.i(TAG, "Radio and Bluetooth shutdown complete.");
Jeff Brownb8203712012-05-31 17:39:13 -0700711 done[0] = true;
712 break;
713 }
Fyodor Kupolov231d57d2017-11-14 17:41:53 -0800714 SystemClock.sleep(RADIOS_STATE_POLL_SLEEP_MS);
Tao Bao81dce662015-06-03 11:42:31 -0700715 delay = endTime - SystemClock.elapsedRealtime();
Jeff Brownb8203712012-05-31 17:39:13 -0700716 }
717 }
718 };
719
720 t.start();
721 try {
722 t.join(timeout);
723 } catch (InterruptedException ex) {
724 }
725 if (!done[0]) {
Ruchi Kandoi20bc30f2017-10-18 13:06:40 -0700726 Log.w(TAG, "Timed out waiting for Radio and Bluetooth shutdown.");
Jeff Brownb8203712012-05-31 17:39:13 -0700727 }
728 }
729
Kenny Rootf547d672010-09-22 10:36:48 -0700730 /**
731 * Do not call this directly. Use {@link #reboot(Context, String, boolean)}
Fyodor Kupolov291f63b2017-08-25 16:59:08 -0700732 * or {@link #shutdown(Context, String, boolean)} instead.
Kenny Rootf547d672010-09-22 10:36:48 -0700733 *
riddle_hsud3b37172015-03-19 01:11:55 +0800734 * @param context Context used to vibrate or null without vibration
Kenny Rootf547d672010-09-22 10:36:48 -0700735 * @param reboot true to reboot or false to shutdown
Yusuke Sato705ffd12015-07-21 15:52:11 -0700736 * @param reason reason for reboot/shutdown
Kenny Rootf547d672010-09-22 10:36:48 -0700737 */
riddle_hsud3b37172015-03-19 01:11:55 +0800738 public static void rebootOrShutdown(final Context context, boolean reboot, String reason) {
Kenny Rootf547d672010-09-22 10:36:48 -0700739 if (reboot) {
740 Log.i(TAG, "Rebooting, reason: " + reason);
Nick Kralevichdbcf2d72013-04-18 14:41:40 -0700741 PowerManagerService.lowLevelReboot(reason);
742 Log.e(TAG, "Reboot failed, will attempt shutdown instead");
Yusuke Sato705ffd12015-07-21 15:52:11 -0700743 reason = null;
riddle_hsud3b37172015-03-19 01:11:55 +0800744 } else if (SHUTDOWN_VIBRATE_MS > 0 && context != null) {
Mike Lockwooda717f642010-04-01 20:01:44 -0700745 // vibrate before shutting down
riddle_hsud3b37172015-03-19 01:11:55 +0800746 Vibrator vibrator = new SystemVibrator(context);
Brad Fitzpatrick26e9cf32010-10-19 09:33:09 -0700747 try {
John Spurlock7b414672014-07-18 13:02:39 -0400748 vibrator.vibrate(SHUTDOWN_VIBRATE_MS, VIBRATION_ATTRIBUTES);
Brad Fitzpatrick26e9cf32010-10-19 09:33:09 -0700749 } catch (Exception e) {
750 // Failure to vibrate shouldn't interrupt shutdown. Just log it.
751 Log.w(TAG, "Failed to vibrate during shutdown.", e);
752 }
753
Mike Lockwooda717f642010-04-01 20:01:44 -0700754 // vibrator is asynchronous so we need to wait to avoid shutting down too soon.
755 try {
756 Thread.sleep(SHUTDOWN_VIBRATE_MS);
Brad Fitzpatricke3316442010-10-14 19:40:56 -0700757 } catch (InterruptedException unused) {
Mike Lockwooda717f642010-04-01 20:01:44 -0700758 }
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -0800759 }
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -0800760 // Shutdown power
Dianne Hackborn55280a92009-05-07 15:53:46 -0700761 Log.i(TAG, "Performing low-level shutdown...");
Yusuke Sato705ffd12015-07-21 15:52:11 -0700762 PowerManagerService.lowLevelShutdown(reason);
Dianne Hackborn55280a92009-05-07 15:53:46 -0700763 }
Tao Bao90237f72015-05-21 16:25:19 -0700764
Fyodor Kupolov291f63b2017-08-25 16:59:08 -0700765 private static void saveMetrics(boolean reboot) {
766 StringBuilder metricValue = new StringBuilder();
767 metricValue.append("reboot:");
768 metricValue.append(reboot ? "y" : "n");
769 final int metricsSize = TRON_METRICS.size();
770 for (int i = 0; i < metricsSize; i++) {
771 final String name = TRON_METRICS.keyAt(i);
772 final long value = TRON_METRICS.valueAt(i);
773 if (value < 0) {
774 Log.e(TAG, "metricEnded wasn't called for " + name);
775 continue;
776 }
777 metricValue.append(',').append(name).append(':').append(value);
778 }
779 File tmp = new File(METRICS_FILE_BASENAME + ".tmp");
780 boolean saved = false;
781 try (FileOutputStream fos = new FileOutputStream(tmp)) {
782 fos.write(metricValue.toString().getBytes(StandardCharsets.UTF_8));
783 saved = true;
784 } catch (IOException e) {
785 Log.e(TAG,"Cannot save shutdown metrics", e);
786 }
787 if (saved) {
788 tmp.renameTo(new File(METRICS_FILE_BASENAME + ".txt"));
789 }
790 }
791
Tao Bao90237f72015-05-21 16:25:19 -0700792 private void uncrypt() {
793 Log.i(TAG, "Calling uncrypt and monitoring the progress...");
794
Tao Baoe8a403d2015-12-31 07:44:55 -0800795 final RecoverySystem.ProgressListener progressListener =
796 new RecoverySystem.ProgressListener() {
797 @Override
798 public void onProgress(int status) {
799 if (status >= 0 && status < 100) {
800 // Scale down to [MOUNT_SERVICE_STOP_PERCENT, 100).
801 status = (int)(status * (100.0 - MOUNT_SERVICE_STOP_PERCENT) / 100);
802 status += MOUNT_SERVICE_STOP_PERCENT;
803 CharSequence msg = mContext.getText(
804 com.android.internal.R.string.reboot_to_update_package);
805 sInstance.setRebootProgress(status, msg);
806 } else if (status == 100) {
807 CharSequence msg = mContext.getText(
808 com.android.internal.R.string.reboot_to_update_reboot);
809 sInstance.setRebootProgress(status, msg);
810 } else {
811 // Ignored
812 }
813 }
814 };
815
Tao Bao90237f72015-05-21 16:25:19 -0700816 final boolean[] done = new boolean[1];
817 done[0] = false;
818 Thread t = new Thread() {
819 @Override
820 public void run() {
Tao Baoe8a403d2015-12-31 07:44:55 -0800821 RecoverySystem rs = (RecoverySystem) mContext.getSystemService(
822 Context.RECOVERY_SERVICE);
823 String filename = null;
Tao Bao90237f72015-05-21 16:25:19 -0700824 try {
Tao Baoe8a403d2015-12-31 07:44:55 -0800825 filename = FileUtils.readTextFile(RecoverySystem.UNCRYPT_PACKAGE_FILE, 0, null);
826 rs.processPackage(mContext, new File(filename), progressListener);
827 } catch (IOException e) {
828 Log.e(TAG, "Error uncrypting file", e);
Tao Bao90237f72015-05-21 16:25:19 -0700829 }
830 done[0] = true;
831 }
832 };
833 t.start();
834
835 try {
836 t.join(MAX_UNCRYPT_WAIT_TIME);
837 } catch (InterruptedException unused) {
838 }
839 if (!done[0]) {
840 Log.w(TAG, "Timed out waiting for uncrypt.");
Tianjie Xu036d0862016-09-24 15:39:56 -0700841 final int uncryptTimeoutError = 100;
842 String timeoutMessage = String.format("uncrypt_time: %d\n" + "uncrypt_error: %d\n",
843 MAX_UNCRYPT_WAIT_TIME / 1000, uncryptTimeoutError);
844 try {
845 FileUtils.stringToFile(RecoverySystem.UNCRYPT_STATUS_FILE, timeoutMessage);
846 } catch (IOException e) {
847 Log.e(TAG, "Failed to write timeout message to uncrypt status", e);
848 }
Tao Bao90237f72015-05-21 16:25:19 -0700849 }
850 }
Dianne Hackborn55280a92009-05-07 15:53:46 -0700851}