blob: bc722f18165008da999a5d05e85f778d9e8a4c21 [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;
23import android.app.ProgressDialog;
Pavel Grafovce72ef02018-01-10 17:14:11 +000024import android.app.admin.SecurityLog;
Dianne Hackborn55280a92009-05-07 15:53:46 -070025import android.content.BroadcastReceiver;
26import android.content.Context;
27import android.content.DialogInterface;
28import android.content.Intent;
Joe Onoratod208e702010-10-08 16:22:43 -040029import android.content.IntentFilter;
Jason Monkfd279662017-06-29 19:37:48 -040030import android.media.AudioAttributes;
Tao Baoe8a403d2015-12-31 07:44:55 -080031import android.os.FileUtils;
Dianne Hackborn55280a92009-05-07 15:53:46 -070032import android.os.Handler;
Dianne Hackbornf99ae762010-03-08 12:43:51 -080033import android.os.PowerManager;
Tao Baoe8a403d2015-12-31 07:44:55 -080034import android.os.RecoverySystem;
Dianne Hackborn55280a92009-05-07 15:53:46 -070035import android.os.RemoteException;
Dianne Hackborn55280a92009-05-07 15:53:46 -070036import android.os.ServiceManager;
37import android.os.SystemClock;
Kenny Rootf547d672010-09-22 10:36:48 -070038import android.os.SystemProperties;
Jason Monkfd279662017-06-29 19:37:48 -040039import android.os.SystemVibrator;
Fyodor Kupolov6e3461b2017-08-10 17:00:43 -070040import android.os.Trace;
Dianne Hackborn5ac72a22012-08-29 18:32:08 -070041import android.os.UserHandle;
Benjamin Franzbff46ba2015-03-05 18:33:51 +000042import android.os.UserManager;
Mike Lockwooda717f642010-04-01 20:01:44 -070043import android.os.Vibrator;
Shuo Qian29131642019-12-09 14:04:56 -080044import android.telephony.TelephonyManager;
Fyodor Kupolov291f63b2017-08-25 16:59:08 -070045import android.util.ArrayMap;
Jason Monkfd279662017-06-29 19:37:48 -040046import android.util.Log;
Jerry Chang1f823472019-12-13 19:07:52 +080047import android.util.Slog;
Fyodor Kupolov6e3461b2017-08-10 17:00:43 -070048import android.util.TimingsTraceLog;
Jason Monkfd279662017-06-29 19:37:48 -040049import android.view.WindowManager;
Lucas Dupin527aad12017-07-21 13:50:25 -070050
Jason Monkb4302182017-08-04 13:39:17 -040051import com.android.server.LocalServices;
Robert Horvathe1b6efd2019-11-05 10:03:52 +010052import com.android.server.RescueParty;
Brian Carlstromff1ec4d2014-03-17 15:21:35 -070053import com.android.server.pm.PackageManagerService;
Jason Monkb4302182017-08-04 13:39:17 -040054import com.android.server.statusbar.StatusBarManagerInternal;
Jeff Brown7304c342012-05-11 18:42:42 -070055
Tao Bao90237f72015-05-21 16:25:19 -070056import java.io.File;
Fyodor Kupolov291f63b2017-08-25 16:59:08 -070057import java.io.FileOutputStream;
Tao Bao90237f72015-05-21 16:25:19 -070058import java.io.IOException;
Fyodor Kupolov291f63b2017-08-25 16:59:08 -070059import java.nio.charset.StandardCharsets;
Tao Bao90237f72015-05-21 16:25:19 -070060
Dianne Hackborn55280a92009-05-07 15:53:46 -070061public final class ShutdownThread extends Thread {
62 // constants
63 private static final String TAG = "ShutdownThread";
Fyodor Kupolov231d57d2017-11-14 17:41:53 -080064 private static final int ACTION_DONE_POLL_WAIT_MS = 500;
65 private static final int RADIOS_STATE_POLL_SLEEP_MS = 100;
Dianne Hackborn55280a92009-05-07 15:53:46 -070066 // maximum time we wait for the shutdown broadcast before going on.
67 private static final int MAX_BROADCAST_TIME = 10*1000;
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -080068 private static final int MAX_SHUTDOWN_WAIT_TIME = 20*1000;
Jeff Brownb8203712012-05-31 17:39:13 -070069 private static final int MAX_RADIO_WAIT_TIME = 12*1000;
Adam Seatonb57e6562016-08-30 22:14:47 +000070 private static final int MAX_UNCRYPT_WAIT_TIME = 15*60*1000;
Tao Bao81dce662015-06-03 11:42:31 -070071 // constants for progress bar. the values are roughly estimated based on timeout.
72 private static final int BROADCAST_STOP_PERCENT = 2;
73 private static final int ACTIVITY_MANAGER_STOP_PERCENT = 4;
74 private static final int PACKAGE_MANAGER_STOP_PERCENT = 6;
75 private static final int RADIO_STOP_PERCENT = 18;
76 private static final int MOUNT_SERVICE_STOP_PERCENT = 20;
Mike Lockwooda717f642010-04-01 20:01:44 -070077
78 // length of vibration before shutting down
79 private static final int SHUTDOWN_VIBRATE_MS = 500;
Tao Bao90237f72015-05-21 16:25:19 -070080
Dianne Hackborn55280a92009-05-07 15:53:46 -070081 // state tracking
Adam Lesinskia82b6262017-03-21 16:56:17 -070082 private static final Object sIsStartedGuard = new Object();
Dianne Hackborn55280a92009-05-07 15:53:46 -070083 private static boolean sIsStarted = false;
Tao Bao90237f72015-05-21 16:25:19 -070084
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -080085 private static boolean mReboot;
Dianne Hackborn19caadc2012-04-20 17:49:10 -070086 private static boolean mRebootSafeMode;
Tao Baoe8a403d2015-12-31 07:44:55 -080087 private static boolean mRebootHasProgressBar;
Yusuke Sato705ffd12015-07-21 15:52:11 -070088 private static String mReason;
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -080089
Kenny Rootf547d672010-09-22 10:36:48 -070090 // Provides shutdown assurance in case the system_server is killed
91 public static final String SHUTDOWN_ACTION_PROPERTY = "sys.shutdown.requested";
92
Dianne Hackborn19caadc2012-04-20 17:49:10 -070093 // Indicates whether we are rebooting into safe mode
94 public static final String REBOOT_SAFEMODE_PROPERTY = "persist.sys.safemode";
dcashmanf44f5a42016-03-02 16:46:40 -080095 public static final String RO_SAFEMODE_PROPERTY = "ro.sys.safemode";
Dianne Hackborn19caadc2012-04-20 17:49:10 -070096
Dianne Hackborn55280a92009-05-07 15:53:46 -070097 // static instance of this thread
98 private static final ShutdownThread sInstance = new ShutdownThread();
John Spurlock7b414672014-07-18 13:02:39 -040099
100 private static final AudioAttributes VIBRATION_ATTRIBUTES = new AudioAttributes.Builder()
101 .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
102 .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
103 .build();
104
Fyodor Kupolov291f63b2017-08-25 16:59:08 -0700105 // Metrics that will be reported to tron after reboot
106 private static final ArrayMap<String, Long> TRON_METRICS = new ArrayMap<>();
107
108 // File to use for save metrics
109 private static final String METRICS_FILE_BASENAME = "/data/system/shutdown-metrics";
110
111 // Metrics names to be persisted in shutdown-metrics file
112 private static String METRIC_SYSTEM_SERVER = "shutdown_system_server";
113 private static String METRIC_SEND_BROADCAST = "shutdown_send_shutdown_broadcast";
114 private static String METRIC_AM = "shutdown_activity_manager";
115 private static String METRIC_PM = "shutdown_package_manager";
116 private static String METRIC_RADIOS = "shutdown_radios";
Fyodor Kupolov291f63b2017-08-25 16:59:08 -0700117 private static String METRIC_RADIO = "shutdown_radio";
Tej Singh1ea42892018-01-19 09:27:00 -0800118 private static String METRIC_SHUTDOWN_TIME_START = "begin_shutdown";
Fyodor Kupolov291f63b2017-08-25 16:59:08 -0700119
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -0800120 private final Object mActionDoneSync = new Object();
121 private boolean mActionDone;
Dianne Hackborn55280a92009-05-07 15:53:46 -0700122 private Context mContext;
Dianne Hackbornf99ae762010-03-08 12:43:51 -0800123 private PowerManager mPowerManager;
Mattias Larssoncd4e4272010-09-28 14:34:15 +0200124 private PowerManager.WakeLock mCpuWakeLock;
125 private PowerManager.WakeLock mScreenWakeLock;
Dianne Hackborn55280a92009-05-07 15:53:46 -0700126 private Handler mHandler;
Jean-Baptiste Queru6e85ad72012-06-11 12:20:36 -0700127
128 private static AlertDialog sConfirmDialog;
Tao Bao90237f72015-05-21 16:25:19 -0700129 private ProgressDialog mProgressDialog;
130
Dianne Hackborn55280a92009-05-07 15:53:46 -0700131 private ShutdownThread() {
132 }
Tao Bao90237f72015-05-21 16:25:19 -0700133
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -0800134 /**
Dianne Hackborn55280a92009-05-07 15:53:46 -0700135 * Request a clean shutdown, waiting for subsystems to clean up their
136 * state etc. Must be called from a Looper thread in which its UI
137 * is shown.
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -0800138 *
Adam Lesinskia82b6262017-03-21 16:56:17 -0700139 * @param context Context used to display the shutdown progress dialog. This must be a context
140 * suitable for displaying UI (aka Themable).
Yusuke Sato705ffd12015-07-21 15:52:11 -0700141 * @param reason code to pass to android_reboot() (e.g. "userrequested"), or null.
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -0800142 * @param confirm true if user confirmation is needed before shutting down.
Dianne Hackborn55280a92009-05-07 15:53:46 -0700143 */
Yusuke Sato705ffd12015-07-21 15:52:11 -0700144 public static void shutdown(final Context context, String reason, boolean confirm) {
Dianne Hackborn19caadc2012-04-20 17:49:10 -0700145 mReboot = false;
146 mRebootSafeMode = false;
Yusuke Sato705ffd12015-07-21 15:52:11 -0700147 mReason = reason;
Dianne Hackborn19caadc2012-04-20 17:49:10 -0700148 shutdownInner(context, confirm);
149 }
150
Adam Lesinskia82b6262017-03-21 16:56:17 -0700151 private static void shutdownInner(final Context context, boolean confirm) {
152 // ShutdownThread is called from many places, so best to verify here that the context passed
153 // in is themed.
154 context.assertRuntimeOverlayThemable();
155
Dianne Hackborn55280a92009-05-07 15:53:46 -0700156 // ensure that only one thread is trying to power down.
157 // any additional calls are just returned
Mike Lockwoodd67b2362010-07-26 07:18:21 -0400158 synchronized (sIsStartedGuard) {
Dianne Hackborn55280a92009-05-07 15:53:46 -0700159 if (sIsStarted) {
160 Log.d(TAG, "Request to shutdown already running, returning.");
161 return;
162 }
163 }
164
Joe Onoratod208e702010-10-08 16:22:43 -0400165 final int longPressBehavior = context.getResources().getInteger(
166 com.android.internal.R.integer.config_longPressOnPowerBehavior);
Dianne Hackborn19caadc2012-04-20 17:49:10 -0700167 final int resourceId = mRebootSafeMode
168 ? com.android.internal.R.string.reboot_safemode_confirm
169 : (longPressBehavior == 2
170 ? com.android.internal.R.string.shutdown_confirm_question
171 : com.android.internal.R.string.shutdown_confirm);
Joe Onoratod208e702010-10-08 16:22:43 -0400172
173 Log.d(TAG, "Notifying thread to start shutdown longPressBehavior=" + longPressBehavior);
Dianne Hackborn55280a92009-05-07 15:53:46 -0700174
175 if (confirm) {
Joe Onoratod208e702010-10-08 16:22:43 -0400176 final CloseDialogReceiver closer = new CloseDialogReceiver(context);
Jean-Baptiste Queru6e85ad72012-06-11 12:20:36 -0700177 if (sConfirmDialog != null) {
178 sConfirmDialog.dismiss();
179 }
180 sConfirmDialog = new AlertDialog.Builder(context)
Dianne Hackborn19caadc2012-04-20 17:49:10 -0700181 .setTitle(mRebootSafeMode
182 ? com.android.internal.R.string.reboot_safemode_title
183 : com.android.internal.R.string.power_off)
Joe Onoratod208e702010-10-08 16:22:43 -0400184 .setMessage(resourceId)
Dianne Hackborn55280a92009-05-07 15:53:46 -0700185 .setPositiveButton(com.android.internal.R.string.yes, new DialogInterface.OnClickListener() {
186 public void onClick(DialogInterface dialog, int which) {
187 beginShutdownSequence(context);
188 }
189 })
190 .setNegativeButton(com.android.internal.R.string.no, null)
191 .create();
Jean-Baptiste Queru6e85ad72012-06-11 12:20:36 -0700192 closer.dialog = sConfirmDialog;
193 sConfirmDialog.setOnDismissListener(closer);
194 sConfirmDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
195 sConfirmDialog.show();
Dianne Hackborn55280a92009-05-07 15:53:46 -0700196 } else {
197 beginShutdownSequence(context);
198 }
199 }
200
Joe Onoratod208e702010-10-08 16:22:43 -0400201 private static class CloseDialogReceiver extends BroadcastReceiver
202 implements DialogInterface.OnDismissListener {
203 private Context mContext;
204 public Dialog dialog;
205
206 CloseDialogReceiver(Context context) {
207 mContext = context;
208 IntentFilter filter = new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
209 context.registerReceiver(this, filter);
210 }
211
212 @Override
213 public void onReceive(Context context, Intent intent) {
214 dialog.cancel();
215 }
216
217 public void onDismiss(DialogInterface unused) {
218 mContext.unregisterReceiver(this);
219 }
220 }
221
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -0800222 /**
223 * Request a clean shutdown, waiting for subsystems to clean up their
224 * state etc. Must be called from a Looper thread in which its UI
225 * is shown.
226 *
Adam Lesinskia82b6262017-03-21 16:56:17 -0700227 * @param context Context used to display the shutdown progress dialog. This must be a context
228 * suitable for displaying UI (aka Themable).
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -0800229 * @param reason code to pass to the kernel (e.g. "recovery"), or null.
230 * @param confirm true if user confirmation is needed before shutting down.
231 */
232 public static void reboot(final Context context, String reason, boolean confirm) {
233 mReboot = true;
Dianne Hackborn19caadc2012-04-20 17:49:10 -0700234 mRebootSafeMode = false;
Tao Baoe8a403d2015-12-31 07:44:55 -0800235 mRebootHasProgressBar = false;
Yusuke Sato705ffd12015-07-21 15:52:11 -0700236 mReason = reason;
Dianne Hackborn19caadc2012-04-20 17:49:10 -0700237 shutdownInner(context, confirm);
238 }
239
240 /**
241 * Request a reboot into safe mode. Must be called from a Looper thread in which its UI
242 * is shown.
243 *
Adam Lesinskia82b6262017-03-21 16:56:17 -0700244 * @param context Context used to display the shutdown progress dialog. This must be a context
245 * suitable for displaying UI (aka Themable).
Dianne Hackborn19caadc2012-04-20 17:49:10 -0700246 * @param confirm true if user confirmation is needed before shutting down.
247 */
248 public static void rebootSafeMode(final Context context, boolean confirm) {
Benjamin Franzbff46ba2015-03-05 18:33:51 +0000249 UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE);
250 if (um.hasUserRestriction(UserManager.DISALLOW_SAFE_BOOT)) {
251 return;
252 }
253
Dianne Hackborn19caadc2012-04-20 17:49:10 -0700254 mReboot = true;
255 mRebootSafeMode = true;
Tao Baoe8a403d2015-12-31 07:44:55 -0800256 mRebootHasProgressBar = false;
Yusuke Sato705ffd12015-07-21 15:52:11 -0700257 mReason = null;
Dianne Hackborn19caadc2012-04-20 17:49:10 -0700258 shutdownInner(context, confirm);
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -0800259 }
260
Jason Monkfd279662017-06-29 19:37:48 -0400261 private static ProgressDialog showShutdownDialog(Context context) {
Tao Bao81dce662015-06-03 11:42:31 -0700262 // Throw up a system dialog to indicate the device is rebooting / shutting down.
Dianne Hackborn55280a92009-05-07 15:53:46 -0700263 ProgressDialog pd = new ProgressDialog(context);
Tao Bao81dce662015-06-03 11:42:31 -0700264
Tao Baoe8a403d2015-12-31 07:44:55 -0800265 // Path 1: Reboot to recovery for update
Tianjie Xu3a66fc42017-06-09 15:50:14 -0700266 // Condition: mReason startswith REBOOT_RECOVERY_UPDATE
Tao Baoe8a403d2015-12-31 07:44:55 -0800267 //
268 // Path 1a: uncrypt needed
269 // Condition: if /cache/recovery/uncrypt_file exists but
270 // /cache/recovery/block.map doesn't.
271 // UI: determinate progress bar (mRebootHasProgressBar == True)
272 //
273 // * Path 1a is expected to be removed once the GmsCore shipped on
274 // device always calls uncrypt prior to reboot.
275 //
276 // Path 1b: uncrypt already done
277 // UI: spinning circle only (no progress bar)
Tao Bao81dce662015-06-03 11:42:31 -0700278 //
279 // Path 2: Reboot to recovery for factory reset
Yusuke Sato705ffd12015-07-21 15:52:11 -0700280 // Condition: mReason == REBOOT_RECOVERY
Tao Bao81dce662015-06-03 11:42:31 -0700281 // UI: spinning circle only (no progress bar)
282 //
283 // Path 3: Regular reboot / shutdown
284 // Condition: Otherwise
285 // UI: spinning circle only (no progress bar)
Tianjie Xu3a66fc42017-06-09 15:50:14 -0700286
287 // mReason could be "recovery-update" or "recovery-update,quiescent".
288 if (mReason != null && mReason.startsWith(PowerManager.REBOOT_RECOVERY_UPDATE)) {
Tao Baoe8a403d2015-12-31 07:44:55 -0800289 // We need the progress bar if uncrypt will be invoked during the
290 // reboot, which might be time-consuming.
291 mRebootHasProgressBar = RecoverySystem.UNCRYPT_PACKAGE_FILE.exists()
292 && !(RecoverySystem.BLOCK_MAP_FILE.exists());
293 pd.setTitle(context.getText(com.android.internal.R.string.reboot_to_update_title));
294 if (mRebootHasProgressBar) {
Tao Bao81dce662015-06-03 11:42:31 -0700295 pd.setMax(100);
Tao Bao81dce662015-06-03 11:42:31 -0700296 pd.setProgress(0);
297 pd.setIndeterminate(false);
Tao Baoe8a403d2015-12-31 07:44:55 -0800298 pd.setProgressNumberFormat(null);
299 pd.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
Tao Bao81dce662015-06-03 11:42:31 -0700300 pd.setMessage(context.getText(
Tao Baoe8a403d2015-12-31 07:44:55 -0800301 com.android.internal.R.string.reboot_to_update_prepare));
302 } else {
Jason Monkb4302182017-08-04 13:39:17 -0400303 if (showSysuiReboot()) {
304 return null;
305 }
Tao Bao81dce662015-06-03 11:42:31 -0700306 pd.setIndeterminate(true);
Tao Baoe8a403d2015-12-31 07:44:55 -0800307 pd.setMessage(context.getText(
308 com.android.internal.R.string.reboot_to_update_reboot));
Tao Bao81dce662015-06-03 11:42:31 -0700309 }
Tianjie Xu3a66fc42017-06-09 15:50:14 -0700310 } else if (mReason != null && mReason.equals(PowerManager.REBOOT_RECOVERY)) {
Robert Horvathe1b6efd2019-11-05 10:03:52 +0100311 if (showSysuiReboot()) {
312 return null;
313 } else if (RescueParty.isAttemptingFactoryReset()) {
Jeff Sharkeyb4f36972017-08-02 14:33:04 -0600314 // We're not actually doing a factory reset yet; we're rebooting
315 // to ask the user if they'd like to reset, so give them a less
316 // scary dialog message.
317 pd.setTitle(context.getText(com.android.internal.R.string.power_off));
318 pd.setMessage(context.getText(com.android.internal.R.string.shutdown_progress));
319 pd.setIndeterminate(true);
320 } else {
321 // Factory reset path. Set the dialog message accordingly.
322 pd.setTitle(context.getText(com.android.internal.R.string.reboot_to_reset_title));
323 pd.setMessage(context.getText(
324 com.android.internal.R.string.reboot_to_reset_message));
325 pd.setIndeterminate(true);
326 }
Tao Bao90237f72015-05-21 16:25:19 -0700327 } else {
Jason Monkb4302182017-08-04 13:39:17 -0400328 if (showSysuiReboot()) {
329 return null;
330 }
Tao Bao90237f72015-05-21 16:25:19 -0700331 pd.setTitle(context.getText(com.android.internal.R.string.power_off));
Tao Bao81dce662015-06-03 11:42:31 -0700332 pd.setMessage(context.getText(com.android.internal.R.string.shutdown_progress));
333 pd.setIndeterminate(true);
Tao Bao90237f72015-05-21 16:25:19 -0700334 }
Dianne Hackborn55280a92009-05-07 15:53:46 -0700335 pd.setCancelable(false);
336 pd.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
Dianne Hackborn55280a92009-05-07 15:53:46 -0700337
338 pd.show();
Jason Monkfd279662017-06-29 19:37:48 -0400339 return pd;
340 }
Dianne Hackborn55280a92009-05-07 15:53:46 -0700341
Jason Monkb4302182017-08-04 13:39:17 -0400342 private static boolean showSysuiReboot() {
343 Log.d(TAG, "Attempting to use SysUI shutdown UI");
344 try {
345 StatusBarManagerInternal service = LocalServices.getService(
346 StatusBarManagerInternal.class);
347 if (service.showShutdownUi(mReboot, mReason)) {
348 // Sysui will handle shutdown UI.
349 Log.d(TAG, "SysUI handling shutdown UI");
350 return true;
351 }
352 } catch (Exception e) {
353 // If anything went wrong, ignore it and use fallback ui
354 }
355 Log.d(TAG, "SysUI is unavailable");
356 return false;
357 }
358
Jason Monkfd279662017-06-29 19:37:48 -0400359 private static void beginShutdownSequence(Context context) {
360 synchronized (sIsStartedGuard) {
361 if (sIsStarted) {
362 Log.d(TAG, "Shutdown sequence already running, returning.");
363 return;
364 }
365 sIsStarted = true;
366 }
367
368 sInstance.mProgressDialog = showShutdownDialog(context);
Dianne Hackborn55280a92009-05-07 15:53:46 -0700369 sInstance.mContext = context;
Dianne Hackbornf99ae762010-03-08 12:43:51 -0800370 sInstance.mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
Mattias Larssoncd4e4272010-09-28 14:34:15 +0200371
372 // make sure we never fall asleep again
373 sInstance.mCpuWakeLock = null;
374 try {
375 sInstance.mCpuWakeLock = sInstance.mPowerManager.newWakeLock(
376 PowerManager.PARTIAL_WAKE_LOCK, TAG + "-cpu");
377 sInstance.mCpuWakeLock.setReferenceCounted(false);
378 sInstance.mCpuWakeLock.acquire();
379 } catch (SecurityException e) {
380 Log.w(TAG, "No permission to acquire wake lock", e);
381 sInstance.mCpuWakeLock = null;
382 }
383
384 // also make sure the screen stays on for better user experience
385 sInstance.mScreenWakeLock = null;
Dianne Hackbornf99ae762010-03-08 12:43:51 -0800386 if (sInstance.mPowerManager.isScreenOn()) {
387 try {
Mattias Larssoncd4e4272010-09-28 14:34:15 +0200388 sInstance.mScreenWakeLock = sInstance.mPowerManager.newWakeLock(
389 PowerManager.FULL_WAKE_LOCK, TAG + "-screen");
390 sInstance.mScreenWakeLock.setReferenceCounted(false);
391 sInstance.mScreenWakeLock.acquire();
Dianne Hackbornf99ae762010-03-08 12:43:51 -0800392 } catch (SecurityException e) {
393 Log.w(TAG, "No permission to acquire wake lock", e);
Mattias Larssoncd4e4272010-09-28 14:34:15 +0200394 sInstance.mScreenWakeLock = null;
Dianne Hackbornf99ae762010-03-08 12:43:51 -0800395 }
396 }
Mattias Larssoncd4e4272010-09-28 14:34:15 +0200397
Pavel Grafovce72ef02018-01-10 17:14:11 +0000398 if (SecurityLog.isLoggingEnabled()) {
399 SecurityLog.writeEvent(SecurityLog.TAG_OS_SHUTDOWN);
400 }
401
Mattias Larssoncd4e4272010-09-28 14:34:15 +0200402 // start the thread that initiates shutdown
Dianne Hackborn55280a92009-05-07 15:53:46 -0700403 sInstance.mHandler = new Handler() {
404 };
405 sInstance.start();
406 }
407
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -0800408 void actionDone() {
409 synchronized (mActionDoneSync) {
410 mActionDone = true;
411 mActionDoneSync.notifyAll();
Dianne Hackborn55280a92009-05-07 15:53:46 -0700412 }
413 }
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -0800414
Dianne Hackborn55280a92009-05-07 15:53:46 -0700415 /**
416 * Makes sure we handle the shutdown gracefully.
Myles Watson1f7fa062018-01-05 16:12:54 -0800417 * Shuts off power regardless of radio state if the allotted time has passed.
Dianne Hackborn55280a92009-05-07 15:53:46 -0700418 */
419 public void run() {
Fyodor Kupolov58815ea2017-08-29 12:12:03 -0700420 TimingsTraceLog shutdownTimingLog = newTimingsLog();
421 shutdownTimingLog.traceBegin("SystemServerShutdown");
Tej Singh1ea42892018-01-19 09:27:00 -0800422 metricShutdownStart();
Fyodor Kupolov58815ea2017-08-29 12:12:03 -0700423 metricStarted(METRIC_SYSTEM_SERVER);
424
Dianne Hackborn55280a92009-05-07 15:53:46 -0700425 BroadcastReceiver br = new BroadcastReceiver() {
426 @Override public void onReceive(Context context, Intent intent) {
427 // We don't allow apps to cancel this, so ignore the result.
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -0800428 actionDone();
Dianne Hackborn55280a92009-05-07 15:53:46 -0700429 }
430 };
Kenny Rootf547d672010-09-22 10:36:48 -0700431
432 /*
433 * Write a system property in case the system_server reboots before we
434 * get to the actual hardware restart. If that happens, we'll retry at
435 * the beginning of the SystemServer startup.
436 */
437 {
Yusuke Sato705ffd12015-07-21 15:52:11 -0700438 String reason = (mReboot ? "1" : "0") + (mReason != null ? mReason : "");
Kenny Rootf547d672010-09-22 10:36:48 -0700439 SystemProperties.set(SHUTDOWN_ACTION_PROPERTY, reason);
440 }
441
Dianne Hackborn19caadc2012-04-20 17:49:10 -0700442 /*
443 * If we are rebooting into safe mode, write a system property
444 * indicating so.
445 */
446 if (mRebootSafeMode) {
447 SystemProperties.set(REBOOT_SAFEMODE_PROPERTY, "1");
448 }
449
Jerry Chang1f823472019-12-13 19:07:52 +0800450 shutdownTimingLog.traceBegin("DumpPreRebootInfo");
451 try {
452 Slog.i(TAG, "Logging pre-reboot information...");
453 PreRebootLogger.log(mContext);
454 } catch (Exception e) {
455 Slog.e(TAG, "Failed to log pre-reboot information", e);
456 }
457 shutdownTimingLog.traceEnd(); // DumpPreRebootInfo
458
Fyodor Kupolov291f63b2017-08-25 16:59:08 -0700459 metricStarted(METRIC_SEND_BROADCAST);
Fyodor Kupolov58815ea2017-08-29 12:12:03 -0700460 shutdownTimingLog.traceBegin("SendShutdownBroadcast");
Dianne Hackborn55280a92009-05-07 15:53:46 -0700461 Log.i(TAG, "Sending shutdown broadcast...");
Tao Bao90237f72015-05-21 16:25:19 -0700462
Dianne Hackborn55280a92009-05-07 15:53:46 -0700463 // First send the high-level shut down broadcast.
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -0800464 mActionDone = false;
Martin Wallgrena81d7da2013-02-04 14:26:51 +0100465 Intent intent = new Intent(Intent.ACTION_SHUTDOWN);
Fyodor Kupolov1fc62602018-02-01 15:48:53 -0800466 intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND | Intent.FLAG_RECEIVER_REGISTERED_ONLY);
Martin Wallgrena81d7da2013-02-04 14:26:51 +0100467 mContext.sendOrderedBroadcastAsUser(intent,
Dianne Hackborn5ac72a22012-08-29 18:32:08 -0700468 UserHandle.ALL, null, br, mHandler, 0, null, null);
Tao Bao90237f72015-05-21 16:25:19 -0700469
Mike Lockwood098e58d2010-05-13 16:29:49 -0400470 final long endTime = SystemClock.elapsedRealtime() + MAX_BROADCAST_TIME;
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -0800471 synchronized (mActionDoneSync) {
472 while (!mActionDone) {
Mike Lockwood098e58d2010-05-13 16:29:49 -0400473 long delay = endTime - SystemClock.elapsedRealtime();
Dianne Hackborn55280a92009-05-07 15:53:46 -0700474 if (delay <= 0) {
475 Log.w(TAG, "Shutdown broadcast timed out");
476 break;
Tao Baoe8a403d2015-12-31 07:44:55 -0800477 } else if (mRebootHasProgressBar) {
Tao Bao81dce662015-06-03 11:42:31 -0700478 int status = (int)((MAX_BROADCAST_TIME - delay) * 1.0 *
479 BROADCAST_STOP_PERCENT / MAX_BROADCAST_TIME);
480 sInstance.setRebootProgress(status, null);
Dianne Hackborn55280a92009-05-07 15:53:46 -0700481 }
482 try {
Fyodor Kupolov231d57d2017-11-14 17:41:53 -0800483 mActionDoneSync.wait(Math.min(delay, ACTION_DONE_POLL_WAIT_MS));
Dianne Hackborn55280a92009-05-07 15:53:46 -0700484 } catch (InterruptedException e) {
485 }
486 }
487 }
Tao Baoe8a403d2015-12-31 07:44:55 -0800488 if (mRebootHasProgressBar) {
Tao Bao81dce662015-06-03 11:42:31 -0700489 sInstance.setRebootProgress(BROADCAST_STOP_PERCENT, null);
490 }
Fyodor Kupolov58815ea2017-08-29 12:12:03 -0700491 shutdownTimingLog.traceEnd(); // SendShutdownBroadcast
Fyodor Kupolov291f63b2017-08-25 16:59:08 -0700492 metricEnded(METRIC_SEND_BROADCAST);
Tao Bao90237f72015-05-21 16:25:19 -0700493
Dianne Hackborn55280a92009-05-07 15:53:46 -0700494 Log.i(TAG, "Shutting down activity manager...");
Fyodor Kupolov58815ea2017-08-29 12:12:03 -0700495 shutdownTimingLog.traceBegin("ShutdownActivityManager");
Fyodor Kupolov291f63b2017-08-25 16:59:08 -0700496 metricStarted(METRIC_AM);
Tao Bao90237f72015-05-21 16:25:19 -0700497
Dianne Hackborn55280a92009-05-07 15:53:46 -0700498 final IActivityManager am =
Sudheer Shankafc46e9b2016-10-21 17:55:27 -0700499 IActivityManager.Stub.asInterface(ServiceManager.checkService("activity"));
Dianne Hackborn55280a92009-05-07 15:53:46 -0700500 if (am != null) {
501 try {
502 am.shutdown(MAX_BROADCAST_TIME);
503 } catch (RemoteException e) {
504 }
505 }
Tao Baoe8a403d2015-12-31 07:44:55 -0800506 if (mRebootHasProgressBar) {
Tao Bao81dce662015-06-03 11:42:31 -0700507 sInstance.setRebootProgress(ACTIVITY_MANAGER_STOP_PERCENT, null);
508 }
Fyodor Kupolov58815ea2017-08-29 12:12:03 -0700509 shutdownTimingLog.traceEnd();// ShutdownActivityManager
Fyodor Kupolov291f63b2017-08-25 16:59:08 -0700510 metricEnded(METRIC_AM);
Dianne Hackborn55280a92009-05-07 15:53:46 -0700511
Brian Carlstromff1ec4d2014-03-17 15:21:35 -0700512 Log.i(TAG, "Shutting down package manager...");
Fyodor Kupolov58815ea2017-08-29 12:12:03 -0700513 shutdownTimingLog.traceBegin("ShutdownPackageManager");
Fyodor Kupolov291f63b2017-08-25 16:59:08 -0700514 metricStarted(METRIC_PM);
Brian Carlstromff1ec4d2014-03-17 15:21:35 -0700515
516 final PackageManagerService pm = (PackageManagerService)
517 ServiceManager.getService("package");
518 if (pm != null) {
519 pm.shutdown();
520 }
Tao Baoe8a403d2015-12-31 07:44:55 -0800521 if (mRebootHasProgressBar) {
Tao Bao81dce662015-06-03 11:42:31 -0700522 sInstance.setRebootProgress(PACKAGE_MANAGER_STOP_PERCENT, null);
523 }
Fyodor Kupolov58815ea2017-08-29 12:12:03 -0700524 shutdownTimingLog.traceEnd(); // ShutdownPackageManager
Fyodor Kupolov291f63b2017-08-25 16:59:08 -0700525 metricEnded(METRIC_PM);
Brian Carlstromff1ec4d2014-03-17 15:21:35 -0700526
Matthew Xie96313142012-06-29 16:57:31 -0700527 // Shutdown radios.
Fyodor Kupolov58815ea2017-08-29 12:12:03 -0700528 shutdownTimingLog.traceBegin("ShutdownRadios");
Fyodor Kupolov291f63b2017-08-25 16:59:08 -0700529 metricStarted(METRIC_RADIOS);
Matthew Xie96313142012-06-29 16:57:31 -0700530 shutdownRadios(MAX_RADIO_WAIT_TIME);
Tao Baoe8a403d2015-12-31 07:44:55 -0800531 if (mRebootHasProgressBar) {
Tao Bao81dce662015-06-03 11:42:31 -0700532 sInstance.setRebootProgress(RADIO_STOP_PERCENT, null);
533 }
Fyodor Kupolov58815ea2017-08-29 12:12:03 -0700534 shutdownTimingLog.traceEnd(); // ShutdownRadios
Fyodor Kupolov291f63b2017-08-25 16:59:08 -0700535 metricEnded(METRIC_RADIOS);
Matthew Xie96313142012-06-29 16:57:31 -0700536
Tao Baoe8a403d2015-12-31 07:44:55 -0800537 if (mRebootHasProgressBar) {
Tao Bao81dce662015-06-03 11:42:31 -0700538 sInstance.setRebootProgress(MOUNT_SERVICE_STOP_PERCENT, null);
San Mehat9f7f7ca2010-01-07 11:34:59 -0800539
Tao Baoe8a403d2015-12-31 07:44:55 -0800540 // If it's to reboot to install an update and uncrypt hasn't been
541 // done yet, trigger it now.
Tao Bao90237f72015-05-21 16:25:19 -0700542 uncrypt();
543 }
544
Fyodor Kupolov58815ea2017-08-29 12:12:03 -0700545 shutdownTimingLog.traceEnd(); // SystemServerShutdown
546 metricEnded(METRIC_SYSTEM_SERVER);
Tej Singh1ea42892018-01-19 09:27:00 -0800547 saveMetrics(mReboot, mReason);
Fyodor Kupolovae435372017-11-15 17:03:10 -0800548 // Remaining work will be done by init, including vold shutdown
Yusuke Sato705ffd12015-07-21 15:52:11 -0700549 rebootOrShutdown(mContext, mReboot, mReason);
Kenny Rootf547d672010-09-22 10:36:48 -0700550 }
551
Fyodor Kupolov58815ea2017-08-29 12:12:03 -0700552 private static TimingsTraceLog newTimingsLog() {
553 return new TimingsTraceLog("ShutdownTiming", Trace.TRACE_TAG_SYSTEM_SERVER);
554 }
555
Fyodor Kupolov291f63b2017-08-25 16:59:08 -0700556 private static void metricStarted(String metricKey) {
Fyodor Kupolov58815ea2017-08-29 12:12:03 -0700557 synchronized (TRON_METRICS) {
558 TRON_METRICS.put(metricKey, -1 * SystemClock.elapsedRealtime());
559 }
Fyodor Kupolov291f63b2017-08-25 16:59:08 -0700560 }
561
562 private static void metricEnded(String metricKey) {
Fyodor Kupolov58815ea2017-08-29 12:12:03 -0700563 synchronized (TRON_METRICS) {
564 TRON_METRICS
565 .put(metricKey, SystemClock.elapsedRealtime() + TRON_METRICS.get(metricKey));
566 }
Fyodor Kupolov291f63b2017-08-25 16:59:08 -0700567 }
568
Tej Singh1ea42892018-01-19 09:27:00 -0800569 private static void metricShutdownStart() {
570 synchronized (TRON_METRICS) {
571 TRON_METRICS.put(METRIC_SHUTDOWN_TIME_START, System.currentTimeMillis());
572 }
573 }
574
Tao Bao81dce662015-06-03 11:42:31 -0700575 private void setRebootProgress(final int progress, final CharSequence message) {
Tao Bao90237f72015-05-21 16:25:19 -0700576 mHandler.post(new Runnable() {
577 @Override
578 public void run() {
579 if (mProgressDialog != null) {
580 mProgressDialog.setProgress(progress);
Tao Bao81dce662015-06-03 11:42:31 -0700581 if (message != null) {
582 mProgressDialog.setMessage(message);
583 }
Tao Bao90237f72015-05-21 16:25:19 -0700584 }
585 }
586 });
587 }
588
Tao Bao81dce662015-06-03 11:42:31 -0700589 private void shutdownRadios(final int timeout) {
Jeff Brownb8203712012-05-31 17:39:13 -0700590 // If a radio is wedged, disabling it may hang so we do this work in another thread,
591 // just in case.
592 final long endTime = SystemClock.elapsedRealtime() + timeout;
593 final boolean[] done = new boolean[1];
594 Thread t = new Thread() {
595 public void run() {
Fyodor Kupolov58815ea2017-08-29 12:12:03 -0700596 TimingsTraceLog shutdownTimingsTraceLog = newTimingsLog();
Jeff Brownb8203712012-05-31 17:39:13 -0700597 boolean radioOff;
598
Shuo Qian29131642019-12-09 14:04:56 -0800599 TelephonyManager telephonyManager = mContext.getSystemService(
600 TelephonyManager.class);
Jeff Brownb8203712012-05-31 17:39:13 -0700601
Shuo Qian29131642019-12-09 14:04:56 -0800602 radioOff = telephonyManager == null
603 || !telephonyManager.isAnyRadioPoweredOn();
604 if (!radioOff) {
605 Log.w(TAG, "Turning off cellular radios...");
606 metricStarted(METRIC_RADIO);
607 telephonyManager.shutdownAllRadios();
Jeff Brownb8203712012-05-31 17:39:13 -0700608 }
609
Myles Watson1f7fa062018-01-05 16:12:54 -0800610 Log.i(TAG, "Waiting for Radio...");
Jeff Brownb8203712012-05-31 17:39:13 -0700611
Tao Bao81dce662015-06-03 11:42:31 -0700612 long delay = endTime - SystemClock.elapsedRealtime();
613 while (delay > 0) {
Tao Baoe8a403d2015-12-31 07:44:55 -0800614 if (mRebootHasProgressBar) {
Tao Bao81dce662015-06-03 11:42:31 -0700615 int status = (int)((timeout - delay) * 1.0 *
616 (RADIO_STOP_PERCENT - PACKAGE_MANAGER_STOP_PERCENT) / timeout);
617 status += PACKAGE_MANAGER_STOP_PERCENT;
618 sInstance.setRebootProgress(status, null);
619 }
620
Jeff Brownb8203712012-05-31 17:39:13 -0700621 if (!radioOff) {
Shuo Qian29131642019-12-09 14:04:56 -0800622 radioOff = !telephonyManager.isAnyRadioPoweredOn();
Jeff Brownb8203712012-05-31 17:39:13 -0700623 if (radioOff) {
624 Log.i(TAG, "Radio turned off.");
Fyodor Kupolov291f63b2017-08-25 16:59:08 -0700625 metricEnded(METRIC_RADIO);
Fyodor Kupolov58815ea2017-08-29 12:12:03 -0700626 shutdownTimingsTraceLog
Fyodor Kupolov291f63b2017-08-25 16:59:08 -0700627 .logDuration("ShutdownRadio", TRON_METRICS.get(METRIC_RADIO));
Jeff Brownb8203712012-05-31 17:39:13 -0700628 }
629 }
Jeff Brownb8203712012-05-31 17:39:13 -0700630
Myles Watson1f7fa062018-01-05 16:12:54 -0800631 if (radioOff) {
632 Log.i(TAG, "Radio shutdown complete.");
Jeff Brownb8203712012-05-31 17:39:13 -0700633 done[0] = true;
634 break;
635 }
Fyodor Kupolov231d57d2017-11-14 17:41:53 -0800636 SystemClock.sleep(RADIOS_STATE_POLL_SLEEP_MS);
Tao Bao81dce662015-06-03 11:42:31 -0700637 delay = endTime - SystemClock.elapsedRealtime();
Jeff Brownb8203712012-05-31 17:39:13 -0700638 }
639 }
640 };
641
642 t.start();
643 try {
644 t.join(timeout);
645 } catch (InterruptedException ex) {
646 }
647 if (!done[0]) {
Myles Watson1f7fa062018-01-05 16:12:54 -0800648 Log.w(TAG, "Timed out waiting for Radio shutdown.");
Jeff Brownb8203712012-05-31 17:39:13 -0700649 }
650 }
651
Kenny Rootf547d672010-09-22 10:36:48 -0700652 /**
653 * Do not call this directly. Use {@link #reboot(Context, String, boolean)}
Fyodor Kupolov291f63b2017-08-25 16:59:08 -0700654 * or {@link #shutdown(Context, String, boolean)} instead.
Kenny Rootf547d672010-09-22 10:36:48 -0700655 *
riddle_hsud3b37172015-03-19 01:11:55 +0800656 * @param context Context used to vibrate or null without vibration
Kenny Rootf547d672010-09-22 10:36:48 -0700657 * @param reboot true to reboot or false to shutdown
Yusuke Sato705ffd12015-07-21 15:52:11 -0700658 * @param reason reason for reboot/shutdown
Kenny Rootf547d672010-09-22 10:36:48 -0700659 */
riddle_hsud3b37172015-03-19 01:11:55 +0800660 public static void rebootOrShutdown(final Context context, boolean reboot, String reason) {
Kenny Rootf547d672010-09-22 10:36:48 -0700661 if (reboot) {
662 Log.i(TAG, "Rebooting, reason: " + reason);
Nick Kralevichdbcf2d72013-04-18 14:41:40 -0700663 PowerManagerService.lowLevelReboot(reason);
664 Log.e(TAG, "Reboot failed, will attempt shutdown instead");
Yusuke Sato705ffd12015-07-21 15:52:11 -0700665 reason = null;
riddle_hsud3b37172015-03-19 01:11:55 +0800666 } else if (SHUTDOWN_VIBRATE_MS > 0 && context != null) {
Mike Lockwooda717f642010-04-01 20:01:44 -0700667 // vibrate before shutting down
riddle_hsud3b37172015-03-19 01:11:55 +0800668 Vibrator vibrator = new SystemVibrator(context);
Brad Fitzpatrick26e9cf32010-10-19 09:33:09 -0700669 try {
John Spurlock7b414672014-07-18 13:02:39 -0400670 vibrator.vibrate(SHUTDOWN_VIBRATE_MS, VIBRATION_ATTRIBUTES);
Brad Fitzpatrick26e9cf32010-10-19 09:33:09 -0700671 } catch (Exception e) {
672 // Failure to vibrate shouldn't interrupt shutdown. Just log it.
673 Log.w(TAG, "Failed to vibrate during shutdown.", e);
674 }
675
Mike Lockwooda717f642010-04-01 20:01:44 -0700676 // vibrator is asynchronous so we need to wait to avoid shutting down too soon.
677 try {
678 Thread.sleep(SHUTDOWN_VIBRATE_MS);
Brad Fitzpatricke3316442010-10-14 19:40:56 -0700679 } catch (InterruptedException unused) {
Mike Lockwooda717f642010-04-01 20:01:44 -0700680 }
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -0800681 }
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -0800682 // Shutdown power
Dianne Hackborn55280a92009-05-07 15:53:46 -0700683 Log.i(TAG, "Performing low-level shutdown...");
Yusuke Sato705ffd12015-07-21 15:52:11 -0700684 PowerManagerService.lowLevelShutdown(reason);
Dianne Hackborn55280a92009-05-07 15:53:46 -0700685 }
Tao Bao90237f72015-05-21 16:25:19 -0700686
Tej Singh1ea42892018-01-19 09:27:00 -0800687 private static void saveMetrics(boolean reboot, String reason) {
Fyodor Kupolov291f63b2017-08-25 16:59:08 -0700688 StringBuilder metricValue = new StringBuilder();
689 metricValue.append("reboot:");
690 metricValue.append(reboot ? "y" : "n");
Tej Singh1ea42892018-01-19 09:27:00 -0800691 metricValue.append(",").append("reason:").append(reason);
Fyodor Kupolov291f63b2017-08-25 16:59:08 -0700692 final int metricsSize = TRON_METRICS.size();
693 for (int i = 0; i < metricsSize; i++) {
694 final String name = TRON_METRICS.keyAt(i);
695 final long value = TRON_METRICS.valueAt(i);
696 if (value < 0) {
697 Log.e(TAG, "metricEnded wasn't called for " + name);
698 continue;
699 }
700 metricValue.append(',').append(name).append(':').append(value);
701 }
702 File tmp = new File(METRICS_FILE_BASENAME + ".tmp");
703 boolean saved = false;
704 try (FileOutputStream fos = new FileOutputStream(tmp)) {
705 fos.write(metricValue.toString().getBytes(StandardCharsets.UTF_8));
706 saved = true;
707 } catch (IOException e) {
708 Log.e(TAG,"Cannot save shutdown metrics", e);
709 }
710 if (saved) {
711 tmp.renameTo(new File(METRICS_FILE_BASENAME + ".txt"));
712 }
713 }
714
Tao Bao90237f72015-05-21 16:25:19 -0700715 private void uncrypt() {
716 Log.i(TAG, "Calling uncrypt and monitoring the progress...");
717
Tao Baoe8a403d2015-12-31 07:44:55 -0800718 final RecoverySystem.ProgressListener progressListener =
719 new RecoverySystem.ProgressListener() {
720 @Override
721 public void onProgress(int status) {
722 if (status >= 0 && status < 100) {
723 // Scale down to [MOUNT_SERVICE_STOP_PERCENT, 100).
724 status = (int)(status * (100.0 - MOUNT_SERVICE_STOP_PERCENT) / 100);
725 status += MOUNT_SERVICE_STOP_PERCENT;
726 CharSequence msg = mContext.getText(
727 com.android.internal.R.string.reboot_to_update_package);
728 sInstance.setRebootProgress(status, msg);
729 } else if (status == 100) {
730 CharSequence msg = mContext.getText(
731 com.android.internal.R.string.reboot_to_update_reboot);
732 sInstance.setRebootProgress(status, msg);
733 } else {
734 // Ignored
735 }
736 }
737 };
738
Tao Bao90237f72015-05-21 16:25:19 -0700739 final boolean[] done = new boolean[1];
740 done[0] = false;
741 Thread t = new Thread() {
742 @Override
743 public void run() {
Tao Baoe8a403d2015-12-31 07:44:55 -0800744 RecoverySystem rs = (RecoverySystem) mContext.getSystemService(
745 Context.RECOVERY_SERVICE);
746 String filename = null;
Tao Bao90237f72015-05-21 16:25:19 -0700747 try {
Tao Baoe8a403d2015-12-31 07:44:55 -0800748 filename = FileUtils.readTextFile(RecoverySystem.UNCRYPT_PACKAGE_FILE, 0, null);
749 rs.processPackage(mContext, new File(filename), progressListener);
750 } catch (IOException e) {
751 Log.e(TAG, "Error uncrypting file", e);
Tao Bao90237f72015-05-21 16:25:19 -0700752 }
753 done[0] = true;
754 }
755 };
756 t.start();
757
758 try {
759 t.join(MAX_UNCRYPT_WAIT_TIME);
760 } catch (InterruptedException unused) {
761 }
762 if (!done[0]) {
763 Log.w(TAG, "Timed out waiting for uncrypt.");
Tianjie Xu036d0862016-09-24 15:39:56 -0700764 final int uncryptTimeoutError = 100;
765 String timeoutMessage = String.format("uncrypt_time: %d\n" + "uncrypt_error: %d\n",
766 MAX_UNCRYPT_WAIT_TIME / 1000, uncryptTimeoutError);
767 try {
768 FileUtils.stringToFile(RecoverySystem.UNCRYPT_STATUS_FILE, timeoutMessage);
769 } catch (IOException e) {
770 Log.e(TAG, "Failed to write timeout message to uncrypt status", e);
771 }
Tao Bao90237f72015-05-21 16:25:19 -0700772 }
773 }
Dianne Hackborn55280a92009-05-07 15:53:46 -0700774}